From 55868965ae1fa956c07695d4642e1add8c9450f7 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Wed, 7 Jul 2021 15:34:10 +0200 Subject: [PATCH] Fixed documentation of the new function vmaCreateBufferWithAlignment --- docs/html/globals.html | 3 + docs/html/globals_func.html | 3 + docs/html/search/all_11.js | 119 +- docs/html/search/classes_0.js | 42 +- docs/html/search/defines_0.js | 16 +- docs/html/search/enums_0.js | 12 +- docs/html/search/enumvalues_0.js | 84 +- docs/html/search/files_0.js | 2 +- docs/html/search/functions_0.js | 103 +- docs/html/search/pages_0.js | 2 +- docs/html/search/pages_1.js | 6 +- docs/html/search/pages_2.js | 6 +- docs/html/search/pages_3.js | 2 +- docs/html/search/pages_4.js | 2 +- docs/html/search/pages_5.js | 2 +- docs/html/search/pages_6.js | 2 +- docs/html/search/pages_7.js | 2 +- docs/html/search/pages_8.js | 6 +- docs/html/search/pages_9.js | 4 +- docs/html/search/pages_a.js | 6 +- docs/html/search/typedefs_0.js | 4 +- docs/html/search/typedefs_1.js | 56 +- docs/html/search/variables_0.js | 14 +- docs/html/search/variables_1.js | 12 +- docs/html/search/variables_2.js | 2 +- docs/html/search/variables_3.js | 6 +- docs/html/search/variables_4.js | 4 +- docs/html/search/variables_5.js | 2 +- docs/html/search/variables_6.js | 30 +- docs/html/search/variables_7.js | 2 +- docs/html/search/variables_8.js | 44 +- docs/html/search/variables_9.js | 2 +- docs/html/search/variables_a.js | 2 +- docs/html/search/variables_b.js | 2 +- docs/html/search/variables_c.js | 16 +- docs/html/search/variables_d.js | 36 +- docs/html/vk__mem__alloc_8h.html | 64 + docs/html/vk__mem__alloc_8h_source.html | 30548 +++++++++++----------- include/vk_mem_alloc.h | 6 +- 39 files changed, 15732 insertions(+), 15544 deletions(-) diff --git a/docs/html/globals.html b/docs/html/globals.html index fb5edae..06f4292 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -296,6 +296,9 @@ $(function() {
  • vmaCreateBuffer() : vk_mem_alloc.h
  • +
  • vmaCreateBufferWithAlignment() +: vk_mem_alloc.h +
  • vmaCreateImage() : vk_mem_alloc.h
  • diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index 533bb8d..85841af 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -109,6 +109,9 @@ $(function() {
  • vmaCreateBuffer() : vk_mem_alloc.h
  • +
  • vmaCreateBufferWithAlignment() +: vk_mem_alloc.h +
  • vmaCreateImage() : vk_mem_alloc.h
  • diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index b6cfcad..0ae78c7 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -96,63 +96,64 @@ var searchData= ['vmacheckpoolcorruption_181',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]], ['vmacreateallocator_182',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], ['vmacreatebuffer_183',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]], - ['vmacreateimage_184',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]], - ['vmacreatelostallocation_185',['vmaCreateLostAllocation',['../vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1',1,'vk_mem_alloc.h']]], - ['vmacreatepool_186',['vmaCreatePool',['../vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50',1,'vk_mem_alloc.h']]], - ['vmadefragment_187',['vmaDefragment',['../vk__mem__alloc_8h.html#a9f0f8f56db5f7f57fe4454f465142dac',1,'vk_mem_alloc.h']]], - ['vmadefragmentationbegin_188',['vmaDefragmentationBegin',['../vk__mem__alloc_8h.html#a36ba776fd7fd5cb1e9359fdc0d8e6e8a',1,'vk_mem_alloc.h']]], - ['vmadefragmentationcontext_189',['VmaDefragmentationContext',['../struct_vma_defragmentation_context.html',1,'']]], - ['vmadefragmentationend_190',['vmaDefragmentationEnd',['../vk__mem__alloc_8h.html#a8774e20e91e245aae959ba63efa15dd2',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflagbits_191',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50c',1,'VmaDefragmentationFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a13415cc0b443353a7b5abda300b833fc',1,'VmaDefragmentationFlagBits(): vk_mem_alloc.h']]], - ['vmadefragmentationflags_192',['VmaDefragmentationFlags',['../vk__mem__alloc_8h.html#a88a77cef37e5d3c4fc9eb328885d048d',1,'vk_mem_alloc.h']]], - ['vmadefragmentationinfo_193',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'VmaDefragmentationInfo'],['../vk__mem__alloc_8h.html#a2bf47f96bf92bed2a49461bd9af3acfa',1,'VmaDefragmentationInfo(): vk_mem_alloc.h']]], - ['vmadefragmentationinfo2_194',['VmaDefragmentationInfo2',['../struct_vma_defragmentation_info2.html',1,'VmaDefragmentationInfo2'],['../vk__mem__alloc_8h.html#ad6daeffaa670ce6d11a203a6224c9937',1,'VmaDefragmentationInfo2(): vk_mem_alloc.h']]], - ['vmadefragmentationpassinfo_195',['VmaDefragmentationPassInfo',['../struct_vma_defragmentation_pass_info.html',1,'VmaDefragmentationPassInfo'],['../vk__mem__alloc_8h.html#a72aebd522242d56abea67b4f47f6549e',1,'VmaDefragmentationPassInfo(): vk_mem_alloc.h']]], - ['vmadefragmentationpassmoveinfo_196',['VmaDefragmentationPassMoveInfo',['../struct_vma_defragmentation_pass_move_info.html',1,'VmaDefragmentationPassMoveInfo'],['../vk__mem__alloc_8h.html#ad6799e8e2b1527abfc84d33bc44aeaf5',1,'VmaDefragmentationPassMoveInfo(): vk_mem_alloc.h']]], - ['vmadefragmentationstats_197',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'VmaDefragmentationStats'],['../vk__mem__alloc_8h.html#ad94034192259c2e34a4d1c5e27810403',1,'VmaDefragmentationStats(): vk_mem_alloc.h']]], - ['vmadestroyallocator_198',['vmaDestroyAllocator',['../vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], - ['vmadestroybuffer_199',['vmaDestroyBuffer',['../vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], - ['vmadestroyimage_200',['vmaDestroyImage',['../vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], - ['vmadestroypool_201',['vmaDestroyPool',['../vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1',1,'vk_mem_alloc.h']]], - ['vmadevicememorycallbacks_202',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'VmaDeviceMemoryCallbacks'],['../vk__mem__alloc_8h.html#a77692d3c8770ea8882d573206bd27b2b',1,'VmaDeviceMemoryCallbacks(): vk_mem_alloc.h']]], - ['vmaenddefragmentationpass_203',['vmaEndDefragmentationPass',['../vk__mem__alloc_8h.html#a1b9ffa538bed905af55c747cc48963bd',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindex_204',['vmaFindMemoryTypeIndex',['../vk__mem__alloc_8h.html#aef15a94b58fbcb0fe706d5720e84a74a',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindexforbufferinfo_205',['vmaFindMemoryTypeIndexForBufferInfo',['../vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindexforimageinfo_206',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]], - ['vmaflushallocation_207',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#a30c37c1eec6025f397be41644f48490f',1,'vk_mem_alloc.h']]], - ['vmaflushallocations_208',['vmaFlushAllocations',['../vk__mem__alloc_8h.html#ac3dd00da721875ed99fa8a881922bdfc',1,'vk_mem_alloc.h']]], - ['vmafreememory_209',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a5fea5518972ae9094b1526cbcb19b05f',1,'vk_mem_alloc.h']]], - ['vmafreememorypages_210',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#a834b1e4aef395c0a1d56a28e69a4a17e',1,'vk_mem_alloc.h']]], - ['vmafreestatsstring_211',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], - ['vmagetallocationinfo_212',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], - ['vmagetallocatorinfo_213',['vmaGetAllocatorInfo',['../vk__mem__alloc_8h.html#afa02231a791b37255720d566a52683e7',1,'vk_mem_alloc.h']]], - ['vmagetbudget_214',['vmaGetBudget',['../vk__mem__alloc_8h.html#aec0ed24ebea2d0099eed5f801daaefba',1,'vk_mem_alloc.h']]], - ['vmagetmemoryproperties_215',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], - ['vmagetmemorytypeproperties_216',['vmaGetMemoryTypeProperties',['../vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], - ['vmagetphysicaldeviceproperties_217',['vmaGetPhysicalDeviceProperties',['../vk__mem__alloc_8h.html#aecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], - ['vmagetpoolname_218',['vmaGetPoolName',['../vk__mem__alloc_8h.html#af09b4e4eafdbee812e8d73ddf960f030',1,'vk_mem_alloc.h']]], - ['vmagetpoolstats_219',['vmaGetPoolStats',['../vk__mem__alloc_8h.html#ae8bf76997b234ef68aad922616df4153',1,'vk_mem_alloc.h']]], - ['vmainvalidateallocation_220',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#aaa8412919139ef413a4215ac6a290fae',1,'vk_mem_alloc.h']]], - ['vmainvalidateallocations_221',['vmaInvalidateAllocations',['../vk__mem__alloc_8h.html#ab25b558d75f7378ec944a1522fdcc3c5',1,'vk_mem_alloc.h']]], - ['vmamakepoolallocationslost_222',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]], - ['vmamapmemory_223',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], - ['vmamemoryusage_224',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'VmaMemoryUsage(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'VmaMemoryUsage(): vk_mem_alloc.h']]], - ['vmapool_225',['VmaPool',['../struct_vma_pool.html',1,'']]], - ['vmapoolcreateflagbits_226',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h']]], - ['vmapoolcreateflags_227',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], - ['vmapoolcreateinfo_228',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'VmaPoolCreateInfo(): vk_mem_alloc.h'],['../struct_vma_pool_create_info.html',1,'VmaPoolCreateInfo']]], - ['vmapoolstats_229',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'VmaPoolStats'],['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'VmaPoolStats(): vk_mem_alloc.h']]], - ['vmarecordflagbits_230',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'VmaRecordFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'VmaRecordFlagBits(): vk_mem_alloc.h']]], - ['vmarecordflags_231',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], - ['vmarecordsettings_232',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'VmaRecordSettings'],['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'VmaRecordSettings(): vk_mem_alloc.h']]], - ['vmasetallocationuserdata_233',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], - ['vmasetcurrentframeindex_234',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], - ['vmasetpoolname_235',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], - ['vmastatinfo_236',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'VmaStatInfo(): vk_mem_alloc.h']]], - ['vmastats_237',['VmaStats',['../struct_vma_stats.html',1,'VmaStats'],['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'VmaStats(): vk_mem_alloc.h']]], - ['vmatouchallocation_238',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], - ['vmaunmapmemory_239',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]], - ['vmavulkanfunctions_240',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'VmaVulkanFunctions(): vk_mem_alloc.h'],['../struct_vma_vulkan_functions.html',1,'VmaVulkanFunctions']]], - ['vulkan_20memory_20allocator_241',['Vulkan Memory Allocator',['../index.html',1,'']]], - ['vulkanapiversion_242',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] + ['vmacreatebufferwithalignment_184',['vmaCreateBufferWithAlignment',['../vk__mem__alloc_8h.html#aa06a690013a0d01e60894ac378083834',1,'vk_mem_alloc.h']]], + ['vmacreateimage_185',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]], + ['vmacreatelostallocation_186',['vmaCreateLostAllocation',['../vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1',1,'vk_mem_alloc.h']]], + ['vmacreatepool_187',['vmaCreatePool',['../vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50',1,'vk_mem_alloc.h']]], + ['vmadefragment_188',['vmaDefragment',['../vk__mem__alloc_8h.html#a9f0f8f56db5f7f57fe4454f465142dac',1,'vk_mem_alloc.h']]], + ['vmadefragmentationbegin_189',['vmaDefragmentationBegin',['../vk__mem__alloc_8h.html#a36ba776fd7fd5cb1e9359fdc0d8e6e8a',1,'vk_mem_alloc.h']]], + ['vmadefragmentationcontext_190',['VmaDefragmentationContext',['../struct_vma_defragmentation_context.html',1,'']]], + ['vmadefragmentationend_191',['vmaDefragmentationEnd',['../vk__mem__alloc_8h.html#a8774e20e91e245aae959ba63efa15dd2',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflagbits_192',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50c',1,'VmaDefragmentationFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a13415cc0b443353a7b5abda300b833fc',1,'VmaDefragmentationFlagBits(): vk_mem_alloc.h']]], + ['vmadefragmentationflags_193',['VmaDefragmentationFlags',['../vk__mem__alloc_8h.html#a88a77cef37e5d3c4fc9eb328885d048d',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo_194',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'VmaDefragmentationInfo'],['../vk__mem__alloc_8h.html#a2bf47f96bf92bed2a49461bd9af3acfa',1,'VmaDefragmentationInfo(): vk_mem_alloc.h']]], + ['vmadefragmentationinfo2_195',['VmaDefragmentationInfo2',['../struct_vma_defragmentation_info2.html',1,'VmaDefragmentationInfo2'],['../vk__mem__alloc_8h.html#ad6daeffaa670ce6d11a203a6224c9937',1,'VmaDefragmentationInfo2(): vk_mem_alloc.h']]], + ['vmadefragmentationpassinfo_196',['VmaDefragmentationPassInfo',['../struct_vma_defragmentation_pass_info.html',1,'VmaDefragmentationPassInfo'],['../vk__mem__alloc_8h.html#a72aebd522242d56abea67b4f47f6549e',1,'VmaDefragmentationPassInfo(): vk_mem_alloc.h']]], + ['vmadefragmentationpassmoveinfo_197',['VmaDefragmentationPassMoveInfo',['../struct_vma_defragmentation_pass_move_info.html',1,'VmaDefragmentationPassMoveInfo'],['../vk__mem__alloc_8h.html#ad6799e8e2b1527abfc84d33bc44aeaf5',1,'VmaDefragmentationPassMoveInfo(): vk_mem_alloc.h']]], + ['vmadefragmentationstats_198',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'VmaDefragmentationStats'],['../vk__mem__alloc_8h.html#ad94034192259c2e34a4d1c5e27810403',1,'VmaDefragmentationStats(): vk_mem_alloc.h']]], + ['vmadestroyallocator_199',['vmaDestroyAllocator',['../vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], + ['vmadestroybuffer_200',['vmaDestroyBuffer',['../vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], + ['vmadestroyimage_201',['vmaDestroyImage',['../vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], + ['vmadestroypool_202',['vmaDestroyPool',['../vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1',1,'vk_mem_alloc.h']]], + ['vmadevicememorycallbacks_203',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'VmaDeviceMemoryCallbacks'],['../vk__mem__alloc_8h.html#a77692d3c8770ea8882d573206bd27b2b',1,'VmaDeviceMemoryCallbacks(): vk_mem_alloc.h']]], + ['vmaenddefragmentationpass_204',['vmaEndDefragmentationPass',['../vk__mem__alloc_8h.html#a1b9ffa538bed905af55c747cc48963bd',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindex_205',['vmaFindMemoryTypeIndex',['../vk__mem__alloc_8h.html#aef15a94b58fbcb0fe706d5720e84a74a',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindexforbufferinfo_206',['vmaFindMemoryTypeIndexForBufferInfo',['../vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindexforimageinfo_207',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]], + ['vmaflushallocation_208',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#a30c37c1eec6025f397be41644f48490f',1,'vk_mem_alloc.h']]], + ['vmaflushallocations_209',['vmaFlushAllocations',['../vk__mem__alloc_8h.html#ac3dd00da721875ed99fa8a881922bdfc',1,'vk_mem_alloc.h']]], + ['vmafreememory_210',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a5fea5518972ae9094b1526cbcb19b05f',1,'vk_mem_alloc.h']]], + ['vmafreememorypages_211',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#a834b1e4aef395c0a1d56a28e69a4a17e',1,'vk_mem_alloc.h']]], + ['vmafreestatsstring_212',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], + ['vmagetallocationinfo_213',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], + ['vmagetallocatorinfo_214',['vmaGetAllocatorInfo',['../vk__mem__alloc_8h.html#afa02231a791b37255720d566a52683e7',1,'vk_mem_alloc.h']]], + ['vmagetbudget_215',['vmaGetBudget',['../vk__mem__alloc_8h.html#aec0ed24ebea2d0099eed5f801daaefba',1,'vk_mem_alloc.h']]], + ['vmagetmemoryproperties_216',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], + ['vmagetmemorytypeproperties_217',['vmaGetMemoryTypeProperties',['../vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], + ['vmagetphysicaldeviceproperties_218',['vmaGetPhysicalDeviceProperties',['../vk__mem__alloc_8h.html#aecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], + ['vmagetpoolname_219',['vmaGetPoolName',['../vk__mem__alloc_8h.html#af09b4e4eafdbee812e8d73ddf960f030',1,'vk_mem_alloc.h']]], + ['vmagetpoolstats_220',['vmaGetPoolStats',['../vk__mem__alloc_8h.html#ae8bf76997b234ef68aad922616df4153',1,'vk_mem_alloc.h']]], + ['vmainvalidateallocation_221',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#aaa8412919139ef413a4215ac6a290fae',1,'vk_mem_alloc.h']]], + ['vmainvalidateallocations_222',['vmaInvalidateAllocations',['../vk__mem__alloc_8h.html#ab25b558d75f7378ec944a1522fdcc3c5',1,'vk_mem_alloc.h']]], + ['vmamakepoolallocationslost_223',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]], + ['vmamapmemory_224',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], + ['vmamemoryusage_225',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'VmaMemoryUsage(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'VmaMemoryUsage(): vk_mem_alloc.h']]], + ['vmapool_226',['VmaPool',['../struct_vma_pool.html',1,'']]], + ['vmapoolcreateflagbits_227',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h']]], + ['vmapoolcreateflags_228',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], + ['vmapoolcreateinfo_229',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'VmaPoolCreateInfo(): vk_mem_alloc.h'],['../struct_vma_pool_create_info.html',1,'VmaPoolCreateInfo']]], + ['vmapoolstats_230',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'VmaPoolStats'],['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'VmaPoolStats(): vk_mem_alloc.h']]], + ['vmarecordflagbits_231',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'VmaRecordFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'VmaRecordFlagBits(): vk_mem_alloc.h']]], + ['vmarecordflags_232',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], + ['vmarecordsettings_233',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'VmaRecordSettings'],['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'VmaRecordSettings(): vk_mem_alloc.h']]], + ['vmasetallocationuserdata_234',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], + ['vmasetcurrentframeindex_235',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], + ['vmasetpoolname_236',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], + ['vmastatinfo_237',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'VmaStatInfo(): vk_mem_alloc.h']]], + ['vmastats_238',['VmaStats',['../struct_vma_stats.html',1,'VmaStats'],['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'VmaStats(): vk_mem_alloc.h']]], + ['vmatouchallocation_239',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], + ['vmaunmapmemory_240',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]], + ['vmavulkanfunctions_241',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'VmaVulkanFunctions(): vk_mem_alloc.h'],['../struct_vma_vulkan_functions.html',1,'VmaVulkanFunctions']]], + ['vulkan_20memory_20allocator_242',['Vulkan Memory Allocator',['../index.html',1,'']]], + ['vulkanapiversion_243',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] ]; diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js index 7ca5d5a..2964ab2 100644 --- a/docs/html/search/classes_0.js +++ b/docs/html/search/classes_0.js @@ -1,24 +1,24 @@ var searchData= [ - ['vmaallocation_243',['VmaAllocation',['../struct_vma_allocation.html',1,'']]], - ['vmaallocationcreateinfo_244',['VmaAllocationCreateInfo',['../struct_vma_allocation_create_info.html',1,'']]], - ['vmaallocationinfo_245',['VmaAllocationInfo',['../struct_vma_allocation_info.html',1,'']]], - ['vmaallocator_246',['VmaAllocator',['../struct_vma_allocator.html',1,'']]], - ['vmaallocatorcreateinfo_247',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'']]], - ['vmaallocatorinfo_248',['VmaAllocatorInfo',['../struct_vma_allocator_info.html',1,'']]], - ['vmabudget_249',['VmaBudget',['../struct_vma_budget.html',1,'']]], - ['vmadefragmentationcontext_250',['VmaDefragmentationContext',['../struct_vma_defragmentation_context.html',1,'']]], - ['vmadefragmentationinfo_251',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'']]], - ['vmadefragmentationinfo2_252',['VmaDefragmentationInfo2',['../struct_vma_defragmentation_info2.html',1,'']]], - ['vmadefragmentationpassinfo_253',['VmaDefragmentationPassInfo',['../struct_vma_defragmentation_pass_info.html',1,'']]], - ['vmadefragmentationpassmoveinfo_254',['VmaDefragmentationPassMoveInfo',['../struct_vma_defragmentation_pass_move_info.html',1,'']]], - ['vmadefragmentationstats_255',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'']]], - ['vmadevicememorycallbacks_256',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'']]], - ['vmapool_257',['VmaPool',['../struct_vma_pool.html',1,'']]], - ['vmapoolcreateinfo_258',['VmaPoolCreateInfo',['../struct_vma_pool_create_info.html',1,'']]], - ['vmapoolstats_259',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'']]], - ['vmarecordsettings_260',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'']]], - ['vmastatinfo_261',['VmaStatInfo',['../struct_vma_stat_info.html',1,'']]], - ['vmastats_262',['VmaStats',['../struct_vma_stats.html',1,'']]], - ['vmavulkanfunctions_263',['VmaVulkanFunctions',['../struct_vma_vulkan_functions.html',1,'']]] + ['vmaallocation_244',['VmaAllocation',['../struct_vma_allocation.html',1,'']]], + ['vmaallocationcreateinfo_245',['VmaAllocationCreateInfo',['../struct_vma_allocation_create_info.html',1,'']]], + ['vmaallocationinfo_246',['VmaAllocationInfo',['../struct_vma_allocation_info.html',1,'']]], + ['vmaallocator_247',['VmaAllocator',['../struct_vma_allocator.html',1,'']]], + ['vmaallocatorcreateinfo_248',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'']]], + ['vmaallocatorinfo_249',['VmaAllocatorInfo',['../struct_vma_allocator_info.html',1,'']]], + ['vmabudget_250',['VmaBudget',['../struct_vma_budget.html',1,'']]], + ['vmadefragmentationcontext_251',['VmaDefragmentationContext',['../struct_vma_defragmentation_context.html',1,'']]], + ['vmadefragmentationinfo_252',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'']]], + ['vmadefragmentationinfo2_253',['VmaDefragmentationInfo2',['../struct_vma_defragmentation_info2.html',1,'']]], + ['vmadefragmentationpassinfo_254',['VmaDefragmentationPassInfo',['../struct_vma_defragmentation_pass_info.html',1,'']]], + ['vmadefragmentationpassmoveinfo_255',['VmaDefragmentationPassMoveInfo',['../struct_vma_defragmentation_pass_move_info.html',1,'']]], + ['vmadefragmentationstats_256',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'']]], + ['vmadevicememorycallbacks_257',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'']]], + ['vmapool_258',['VmaPool',['../struct_vma_pool.html',1,'']]], + ['vmapoolcreateinfo_259',['VmaPoolCreateInfo',['../struct_vma_pool_create_info.html',1,'']]], + ['vmapoolstats_260',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'']]], + ['vmarecordsettings_261',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'']]], + ['vmastatinfo_262',['VmaStatInfo',['../struct_vma_stat_info.html',1,'']]], + ['vmastats_263',['VmaStats',['../struct_vma_stats.html',1,'']]], + ['vmavulkanfunctions_264',['VmaVulkanFunctions',['../struct_vma_vulkan_functions.html',1,'']]] ]; diff --git a/docs/html/search/defines_0.js b/docs/html/search/defines_0.js index 273e309..c488423 100644 --- a/docs/html/search/defines_0.js +++ b/docs/html/search/defines_0.js @@ -1,11 +1,11 @@ var searchData= [ - ['vma_5fbind_5fmemory2_481',['VMA_BIND_MEMORY2',['../vk__mem__alloc_8h.html#a88bef97f86d70a34a4c0746e09a2680d',1,'vk_mem_alloc.h']]], - ['vma_5fbuffer_5fdevice_5faddress_482',['VMA_BUFFER_DEVICE_ADDRESS',['../vk__mem__alloc_8h.html#a7f9d5e71b70dd1a137c303a8a8262c10',1,'vk_mem_alloc.h']]], - ['vma_5fdedicated_5fallocation_483',['VMA_DEDICATED_ALLOCATION',['../vk__mem__alloc_8h.html#af7b860e63b96d11e44ae8587ba06bbf4',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fbudget_484',['VMA_MEMORY_BUDGET',['../vk__mem__alloc_8h.html#a05decf1cf4ebf767beba7acca6c1ec3a',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fpriority_485',['VMA_MEMORY_PRIORITY',['../vk__mem__alloc_8h.html#a81af8a3a87e34bbb493848143cde43e4',1,'vk_mem_alloc.h']]], - ['vma_5frecording_5fenabled_486',['VMA_RECORDING_ENABLED',['../vk__mem__alloc_8h.html#a1f0c126759fc96ccb6e2d23c101d770c',1,'vk_mem_alloc.h']]], - ['vma_5fstats_5fstring_5fenabled_487',['VMA_STATS_STRING_ENABLED',['../vk__mem__alloc_8h.html#ae25f0d55fd91cb166f002b63244800e1',1,'vk_mem_alloc.h']]], - ['vma_5fvulkan_5fversion_488',['VMA_VULKAN_VERSION',['../vk__mem__alloc_8h.html#a1a2407c283893638cc039bb31fcd74b6',1,'vk_mem_alloc.h']]] + ['vma_5fbind_5fmemory2_483',['VMA_BIND_MEMORY2',['../vk__mem__alloc_8h.html#a88bef97f86d70a34a4c0746e09a2680d',1,'vk_mem_alloc.h']]], + ['vma_5fbuffer_5fdevice_5faddress_484',['VMA_BUFFER_DEVICE_ADDRESS',['../vk__mem__alloc_8h.html#a7f9d5e71b70dd1a137c303a8a8262c10',1,'vk_mem_alloc.h']]], + ['vma_5fdedicated_5fallocation_485',['VMA_DEDICATED_ALLOCATION',['../vk__mem__alloc_8h.html#af7b860e63b96d11e44ae8587ba06bbf4',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fbudget_486',['VMA_MEMORY_BUDGET',['../vk__mem__alloc_8h.html#a05decf1cf4ebf767beba7acca6c1ec3a',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fpriority_487',['VMA_MEMORY_PRIORITY',['../vk__mem__alloc_8h.html#a81af8a3a87e34bbb493848143cde43e4',1,'vk_mem_alloc.h']]], + ['vma_5frecording_5fenabled_488',['VMA_RECORDING_ENABLED',['../vk__mem__alloc_8h.html#a1f0c126759fc96ccb6e2d23c101d770c',1,'vk_mem_alloc.h']]], + ['vma_5fstats_5fstring_5fenabled_489',['VMA_STATS_STRING_ENABLED',['../vk__mem__alloc_8h.html#ae25f0d55fd91cb166f002b63244800e1',1,'vk_mem_alloc.h']]], + ['vma_5fvulkan_5fversion_490',['VMA_VULKAN_VERSION',['../vk__mem__alloc_8h.html#a1a2407c283893638cc039bb31fcd74b6',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/enums_0.js b/docs/html/search/enums_0.js index 9719a54..52be9af 100644 --- a/docs/html/search/enums_0.js +++ b/docs/html/search/enums_0.js @@ -1,9 +1,9 @@ var searchData= [ - ['vmaallocationcreateflagbits_433',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateflagbits_434',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7c',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflagbits_435',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50c',1,'vk_mem_alloc.h']]], - ['vmamemoryusage_436',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'vk_mem_alloc.h']]], - ['vmapoolcreateflagbits_437',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'vk_mem_alloc.h']]], - ['vmarecordflagbits_438',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'vk_mem_alloc.h']]] + ['vmaallocationcreateflagbits_435',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateflagbits_436',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7c',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflagbits_437',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50c',1,'vk_mem_alloc.h']]], + ['vmamemoryusage_438',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'vk_mem_alloc.h']]], + ['vmapoolcreateflagbits_439',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'vk_mem_alloc.h']]], + ['vmarecordflagbits_440',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/enumvalues_0.js b/docs/html/search/enumvalues_0.js index 217fe70..003ea0e 100644 --- a/docs/html/search/enumvalues_0.js +++ b/docs/html/search/enumvalues_0.js @@ -1,45 +1,45 @@ var searchData= [ - ['vma_5fallocation_5fcreate_5fcan_5fbecome_5flost_5fbit_439',['VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fcan_5fmake_5fother_5flost_5fbit_440',['VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fdedicated_5fmemory_5fbit_441',['VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a3fc311d855c2ff53f1090ef5c722b38f',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fdont_5fbind_5fbit_442',['VMA_ALLOCATION_CREATE_DONT_BIND_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a2310568c62208af432724305fe29ccea',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fflag_5fbits_5fmax_5fenum_443',['VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ae5633ec569f4899cf8f29e7385b2f882',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fmapped_5fbit_444',['VMA_ALLOCATION_CREATE_MAPPED_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a11da372cc3a82931c5e5d6146cd9dd1f',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fnever_5fallocate_5fbit_445',['VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a89759603401014eb325eb22a3839f2ff',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fbest_5ffit_5fbit_446',['VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a839826775c62319466441f86496f036d',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5ffirst_5ffit_5fbit_447',['VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmask_448',['VMA_ALLOCATION_CREATE_STRATEGY_MASK',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8e16845d81ae3d27c47106d4770d5c7e',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ffragmentation_5fbit_449',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a621b704103eb3360230c860acf36e706',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5fmemory_5fbit_450',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8af1210cf591784afa026d94998f735d',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ftime_5fbit_451',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a0729e932b7ea170e3a128cad96c5cf6d',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fworst_5ffit_5fbit_452',['VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ad242a04f802e25fef0b880afe8bb0a62',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fupper_5faddress_5fbit_453',['VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a42ba3a2d2c7117953210b7c3ef8da0df',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fuser_5fdata_5fcopy_5fstring_5fbit_454',['VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597aa6f24f821cd6a7c5e4a443f7bf59c520',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fwithin_5fbudget_5fbit_455',['VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ab8b1764f3e9022368e440c057783b92d',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5famd_5fdevice_5fcoherent_5fmemory_5fbit_456',['VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca2acce4886d8078552efa38878413970f',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fbuffer_5fdevice_5faddress_5fbit_457',['VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca5f1b28b0414319d1687e1f2b30ab0089',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fext_5fmemory_5fbudget_5fbit_458',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4d4687863f7bd4b418c6006dc04400b0',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fext_5fmemory_5fpriority_5fbit_459',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7caffdd7a5169be3dbd7cbf6b3619e4f78a',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fexternally_5fsynchronized_5fbit_460',['VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4816ddaed324ba110172ca608a20f29d',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fflag_5fbits_5fmax_5fenum_461',['VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cae4d5ad929caba5f23eb502b13bd5286c',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fkhr_5fbind_5fmemory2_5fbit_462',['VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca8fb75bf07cd184ab903596295e863dee',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fkhr_5fdedicated_5fallocation_5fbit_463',['VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cace7da7cc6e71a625dfa763c55a597878',1,'vk_mem_alloc.h']]], - ['vma_5fdefragmentation_5fflag_5fbits_5fmax_5fenum_464',['VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50cab87ec33154803bfeb5ac2b379f1d6a97',1,'vk_mem_alloc.h']]], - ['vma_5fdefragmentation_5fflag_5fincremental_465',['VMA_DEFRAGMENTATION_FLAG_INCREMENTAL',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50ca31af49446af2459284a568ce2f3fdd33',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fcopy_466',['VMA_MEMORY_USAGE_CPU_COPY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca416a444d4d0fc20067c3f76f32ff2500',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fonly_467',['VMA_MEMORY_USAGE_CPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu_468',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5flazily_5fallocated_469',['VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca835333d9072db63a653818030e17614d',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5fonly_470',['VMA_MEMORY_USAGE_GPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5fto_5fcpu_471',['VMA_MEMORY_USAGE_GPU_TO_CPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca7b586d2fdaf82a463b58f581ed72be27',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fmax_5fenum_472',['VMA_MEMORY_USAGE_MAX_ENUM',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca091e69437ef693e8d0d287f1c719ba6e',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5funknown_473',['VMA_MEMORY_USAGE_UNKNOWN',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccaf50d27e34e0925cf3a63db8c839121dd',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5falgorithm_5fmask_474',['VMA_POOL_CREATE_ALGORITHM_MASK',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7af4d270f8f42517a0f70037ceb6ac1d9c',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5fbuddy_5falgorithm_5fbit_475',['VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a97a0dc38e5161b780594d998d313d35e',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5fflag_5fbits_5fmax_5fenum_476',['VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a1c7312bea9ea246846b9054fd6bd6aec',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5fignore_5fbuffer_5fimage_5fgranularity_5fbit_477',['VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a9f1a499508a8edb4e8ba40aa0290a3d2',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5flinear_5falgorithm_5fbit_478',['VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a13c8a444197c67866be9cb05599fc726',1,'vk_mem_alloc.h']]], - ['vma_5frecord_5fflag_5fbits_5fmax_5fenum_479',['VMA_RECORD_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a20dd17d69966dbffa054739d6090b85e',1,'vk_mem_alloc.h']]], - ['vma_5frecord_5fflush_5fafter_5fcall_5fbit_480',['VMA_RECORD_FLUSH_AFTER_CALL_BIT',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a8e7ab322e8732654be627c4ea8f36cc7',1,'vk_mem_alloc.h']]] + ['vma_5fallocation_5fcreate_5fcan_5fbecome_5flost_5fbit_441',['VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fcan_5fmake_5fother_5flost_5fbit_442',['VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fdedicated_5fmemory_5fbit_443',['VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a3fc311d855c2ff53f1090ef5c722b38f',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fdont_5fbind_5fbit_444',['VMA_ALLOCATION_CREATE_DONT_BIND_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a2310568c62208af432724305fe29ccea',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fflag_5fbits_5fmax_5fenum_445',['VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ae5633ec569f4899cf8f29e7385b2f882',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fmapped_5fbit_446',['VMA_ALLOCATION_CREATE_MAPPED_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a11da372cc3a82931c5e5d6146cd9dd1f',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fnever_5fallocate_5fbit_447',['VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a89759603401014eb325eb22a3839f2ff',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fbest_5ffit_5fbit_448',['VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a839826775c62319466441f86496f036d',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5ffirst_5ffit_5fbit_449',['VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmask_450',['VMA_ALLOCATION_CREATE_STRATEGY_MASK',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8e16845d81ae3d27c47106d4770d5c7e',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ffragmentation_5fbit_451',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a621b704103eb3360230c860acf36e706',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5fmemory_5fbit_452',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8af1210cf591784afa026d94998f735d',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ftime_5fbit_453',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a0729e932b7ea170e3a128cad96c5cf6d',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fworst_5ffit_5fbit_454',['VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ad242a04f802e25fef0b880afe8bb0a62',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fupper_5faddress_5fbit_455',['VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a42ba3a2d2c7117953210b7c3ef8da0df',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fuser_5fdata_5fcopy_5fstring_5fbit_456',['VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597aa6f24f821cd6a7c5e4a443f7bf59c520',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fwithin_5fbudget_5fbit_457',['VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ab8b1764f3e9022368e440c057783b92d',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5famd_5fdevice_5fcoherent_5fmemory_5fbit_458',['VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca2acce4886d8078552efa38878413970f',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fbuffer_5fdevice_5faddress_5fbit_459',['VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca5f1b28b0414319d1687e1f2b30ab0089',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fext_5fmemory_5fbudget_5fbit_460',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4d4687863f7bd4b418c6006dc04400b0',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fext_5fmemory_5fpriority_5fbit_461',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7caffdd7a5169be3dbd7cbf6b3619e4f78a',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fexternally_5fsynchronized_5fbit_462',['VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4816ddaed324ba110172ca608a20f29d',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fflag_5fbits_5fmax_5fenum_463',['VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cae4d5ad929caba5f23eb502b13bd5286c',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fkhr_5fbind_5fmemory2_5fbit_464',['VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca8fb75bf07cd184ab903596295e863dee',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fkhr_5fdedicated_5fallocation_5fbit_465',['VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cace7da7cc6e71a625dfa763c55a597878',1,'vk_mem_alloc.h']]], + ['vma_5fdefragmentation_5fflag_5fbits_5fmax_5fenum_466',['VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50cab87ec33154803bfeb5ac2b379f1d6a97',1,'vk_mem_alloc.h']]], + ['vma_5fdefragmentation_5fflag_5fincremental_467',['VMA_DEFRAGMENTATION_FLAG_INCREMENTAL',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50ca31af49446af2459284a568ce2f3fdd33',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fcopy_468',['VMA_MEMORY_USAGE_CPU_COPY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca416a444d4d0fc20067c3f76f32ff2500',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fonly_469',['VMA_MEMORY_USAGE_CPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu_470',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5flazily_5fallocated_471',['VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca835333d9072db63a653818030e17614d',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5fonly_472',['VMA_MEMORY_USAGE_GPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5fto_5fcpu_473',['VMA_MEMORY_USAGE_GPU_TO_CPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca7b586d2fdaf82a463b58f581ed72be27',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fmax_5fenum_474',['VMA_MEMORY_USAGE_MAX_ENUM',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca091e69437ef693e8d0d287f1c719ba6e',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5funknown_475',['VMA_MEMORY_USAGE_UNKNOWN',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccaf50d27e34e0925cf3a63db8c839121dd',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5falgorithm_5fmask_476',['VMA_POOL_CREATE_ALGORITHM_MASK',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7af4d270f8f42517a0f70037ceb6ac1d9c',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5fbuddy_5falgorithm_5fbit_477',['VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a97a0dc38e5161b780594d998d313d35e',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5fflag_5fbits_5fmax_5fenum_478',['VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a1c7312bea9ea246846b9054fd6bd6aec',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5fignore_5fbuffer_5fimage_5fgranularity_5fbit_479',['VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a9f1a499508a8edb4e8ba40aa0290a3d2',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5flinear_5falgorithm_5fbit_480',['VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a13c8a444197c67866be9cb05599fc726',1,'vk_mem_alloc.h']]], + ['vma_5frecord_5fflag_5fbits_5fmax_5fenum_481',['VMA_RECORD_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a20dd17d69966dbffa054739d6090b85e',1,'vk_mem_alloc.h']]], + ['vma_5frecord_5fflush_5fafter_5fcall_5fbit_482',['VMA_RECORD_FLUSH_AFTER_CALL_BIT',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a8e7ab322e8732654be627c4ea8f36cc7',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/files_0.js b/docs/html/search/files_0.js index 773665e..4b81803 100644 --- a/docs/html/search/files_0.js +++ b/docs/html/search/files_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['vk_5fmem_5falloc_2eh_264',['vk_mem_alloc.h',['../vk__mem__alloc_8h.html',1,'']]] + ['vk_5fmem_5falloc_2eh_265',['vk_mem_alloc.h',['../vk__mem__alloc_8h.html',1,'']]] ]; diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js index b499356..6bcf2b2 100644 --- a/docs/html/search/functions_0.js +++ b/docs/html/search/functions_0.js @@ -1,54 +1,55 @@ var searchData= [ - ['vmaallocatememory_265',['vmaAllocateMemory',['../vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforbuffer_266',['vmaAllocateMemoryForBuffer',['../vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforimage_267',['vmaAllocateMemoryForImage',['../vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb',1,'vk_mem_alloc.h']]], - ['vmaallocatememorypages_268',['vmaAllocateMemoryPages',['../vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1',1,'vk_mem_alloc.h']]], - ['vmabegindefragmentationpass_269',['vmaBeginDefragmentationPass',['../vk__mem__alloc_8h.html#ac0f01545b6262f7d4d128fc8f8e5c77b',1,'vk_mem_alloc.h']]], - ['vmabindbuffermemory_270',['vmaBindBufferMemory',['../vk__mem__alloc_8h.html#a6b0929b914b60cf2d45cac4bf3547470',1,'vk_mem_alloc.h']]], - ['vmabindbuffermemory2_271',['vmaBindBufferMemory2',['../vk__mem__alloc_8h.html#a927c944f45e0f2941182abb6f608e64a',1,'vk_mem_alloc.h']]], - ['vmabindimagememory_272',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]], - ['vmabindimagememory2_273',['vmaBindImageMemory2',['../vk__mem__alloc_8h.html#aa8251ee81b0045a443e35b8e8aa021bc',1,'vk_mem_alloc.h']]], - ['vmabuildstatsstring_274',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], - ['vmacalculatestats_275',['vmaCalculateStats',['../vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], - ['vmacheckcorruption_276',['vmaCheckCorruption',['../vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98',1,'vk_mem_alloc.h']]], - ['vmacheckpoolcorruption_277',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]], - ['vmacreateallocator_278',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], - ['vmacreatebuffer_279',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]], - ['vmacreateimage_280',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]], - ['vmacreatelostallocation_281',['vmaCreateLostAllocation',['../vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1',1,'vk_mem_alloc.h']]], - ['vmacreatepool_282',['vmaCreatePool',['../vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50',1,'vk_mem_alloc.h']]], - ['vmadefragment_283',['vmaDefragment',['../vk__mem__alloc_8h.html#a9f0f8f56db5f7f57fe4454f465142dac',1,'vk_mem_alloc.h']]], - ['vmadefragmentationbegin_284',['vmaDefragmentationBegin',['../vk__mem__alloc_8h.html#a36ba776fd7fd5cb1e9359fdc0d8e6e8a',1,'vk_mem_alloc.h']]], - ['vmadefragmentationend_285',['vmaDefragmentationEnd',['../vk__mem__alloc_8h.html#a8774e20e91e245aae959ba63efa15dd2',1,'vk_mem_alloc.h']]], - ['vmadestroyallocator_286',['vmaDestroyAllocator',['../vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], - ['vmadestroybuffer_287',['vmaDestroyBuffer',['../vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], - ['vmadestroyimage_288',['vmaDestroyImage',['../vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], - ['vmadestroypool_289',['vmaDestroyPool',['../vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1',1,'vk_mem_alloc.h']]], - ['vmaenddefragmentationpass_290',['vmaEndDefragmentationPass',['../vk__mem__alloc_8h.html#a1b9ffa538bed905af55c747cc48963bd',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindex_291',['vmaFindMemoryTypeIndex',['../vk__mem__alloc_8h.html#aef15a94b58fbcb0fe706d5720e84a74a',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindexforbufferinfo_292',['vmaFindMemoryTypeIndexForBufferInfo',['../vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindexforimageinfo_293',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]], - ['vmaflushallocation_294',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#a30c37c1eec6025f397be41644f48490f',1,'vk_mem_alloc.h']]], - ['vmaflushallocations_295',['vmaFlushAllocations',['../vk__mem__alloc_8h.html#ac3dd00da721875ed99fa8a881922bdfc',1,'vk_mem_alloc.h']]], - ['vmafreememory_296',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a5fea5518972ae9094b1526cbcb19b05f',1,'vk_mem_alloc.h']]], - ['vmafreememorypages_297',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#a834b1e4aef395c0a1d56a28e69a4a17e',1,'vk_mem_alloc.h']]], - ['vmafreestatsstring_298',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], - ['vmagetallocationinfo_299',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], - ['vmagetallocatorinfo_300',['vmaGetAllocatorInfo',['../vk__mem__alloc_8h.html#afa02231a791b37255720d566a52683e7',1,'vk_mem_alloc.h']]], - ['vmagetbudget_301',['vmaGetBudget',['../vk__mem__alloc_8h.html#aec0ed24ebea2d0099eed5f801daaefba',1,'vk_mem_alloc.h']]], - ['vmagetmemoryproperties_302',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], - ['vmagetmemorytypeproperties_303',['vmaGetMemoryTypeProperties',['../vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], - ['vmagetphysicaldeviceproperties_304',['vmaGetPhysicalDeviceProperties',['../vk__mem__alloc_8h.html#aecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], - ['vmagetpoolname_305',['vmaGetPoolName',['../vk__mem__alloc_8h.html#af09b4e4eafdbee812e8d73ddf960f030',1,'vk_mem_alloc.h']]], - ['vmagetpoolstats_306',['vmaGetPoolStats',['../vk__mem__alloc_8h.html#ae8bf76997b234ef68aad922616df4153',1,'vk_mem_alloc.h']]], - ['vmainvalidateallocation_307',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#aaa8412919139ef413a4215ac6a290fae',1,'vk_mem_alloc.h']]], - ['vmainvalidateallocations_308',['vmaInvalidateAllocations',['../vk__mem__alloc_8h.html#ab25b558d75f7378ec944a1522fdcc3c5',1,'vk_mem_alloc.h']]], - ['vmamakepoolallocationslost_309',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]], - ['vmamapmemory_310',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], - ['vmasetallocationuserdata_311',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], - ['vmasetcurrentframeindex_312',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], - ['vmasetpoolname_313',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], - ['vmatouchallocation_314',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], - ['vmaunmapmemory_315',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]] + ['vmaallocatememory_266',['vmaAllocateMemory',['../vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforbuffer_267',['vmaAllocateMemoryForBuffer',['../vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforimage_268',['vmaAllocateMemoryForImage',['../vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb',1,'vk_mem_alloc.h']]], + ['vmaallocatememorypages_269',['vmaAllocateMemoryPages',['../vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1',1,'vk_mem_alloc.h']]], + ['vmabegindefragmentationpass_270',['vmaBeginDefragmentationPass',['../vk__mem__alloc_8h.html#ac0f01545b6262f7d4d128fc8f8e5c77b',1,'vk_mem_alloc.h']]], + ['vmabindbuffermemory_271',['vmaBindBufferMemory',['../vk__mem__alloc_8h.html#a6b0929b914b60cf2d45cac4bf3547470',1,'vk_mem_alloc.h']]], + ['vmabindbuffermemory2_272',['vmaBindBufferMemory2',['../vk__mem__alloc_8h.html#a927c944f45e0f2941182abb6f608e64a',1,'vk_mem_alloc.h']]], + ['vmabindimagememory_273',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]], + ['vmabindimagememory2_274',['vmaBindImageMemory2',['../vk__mem__alloc_8h.html#aa8251ee81b0045a443e35b8e8aa021bc',1,'vk_mem_alloc.h']]], + ['vmabuildstatsstring_275',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], + ['vmacalculatestats_276',['vmaCalculateStats',['../vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], + ['vmacheckcorruption_277',['vmaCheckCorruption',['../vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98',1,'vk_mem_alloc.h']]], + ['vmacheckpoolcorruption_278',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]], + ['vmacreateallocator_279',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], + ['vmacreatebuffer_280',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]], + ['vmacreatebufferwithalignment_281',['vmaCreateBufferWithAlignment',['../vk__mem__alloc_8h.html#aa06a690013a0d01e60894ac378083834',1,'vk_mem_alloc.h']]], + ['vmacreateimage_282',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]], + ['vmacreatelostallocation_283',['vmaCreateLostAllocation',['../vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1',1,'vk_mem_alloc.h']]], + ['vmacreatepool_284',['vmaCreatePool',['../vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50',1,'vk_mem_alloc.h']]], + ['vmadefragment_285',['vmaDefragment',['../vk__mem__alloc_8h.html#a9f0f8f56db5f7f57fe4454f465142dac',1,'vk_mem_alloc.h']]], + ['vmadefragmentationbegin_286',['vmaDefragmentationBegin',['../vk__mem__alloc_8h.html#a36ba776fd7fd5cb1e9359fdc0d8e6e8a',1,'vk_mem_alloc.h']]], + ['vmadefragmentationend_287',['vmaDefragmentationEnd',['../vk__mem__alloc_8h.html#a8774e20e91e245aae959ba63efa15dd2',1,'vk_mem_alloc.h']]], + ['vmadestroyallocator_288',['vmaDestroyAllocator',['../vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], + ['vmadestroybuffer_289',['vmaDestroyBuffer',['../vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], + ['vmadestroyimage_290',['vmaDestroyImage',['../vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], + ['vmadestroypool_291',['vmaDestroyPool',['../vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1',1,'vk_mem_alloc.h']]], + ['vmaenddefragmentationpass_292',['vmaEndDefragmentationPass',['../vk__mem__alloc_8h.html#a1b9ffa538bed905af55c747cc48963bd',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindex_293',['vmaFindMemoryTypeIndex',['../vk__mem__alloc_8h.html#aef15a94b58fbcb0fe706d5720e84a74a',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindexforbufferinfo_294',['vmaFindMemoryTypeIndexForBufferInfo',['../vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindexforimageinfo_295',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]], + ['vmaflushallocation_296',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#a30c37c1eec6025f397be41644f48490f',1,'vk_mem_alloc.h']]], + ['vmaflushallocations_297',['vmaFlushAllocations',['../vk__mem__alloc_8h.html#ac3dd00da721875ed99fa8a881922bdfc',1,'vk_mem_alloc.h']]], + ['vmafreememory_298',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a5fea5518972ae9094b1526cbcb19b05f',1,'vk_mem_alloc.h']]], + ['vmafreememorypages_299',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#a834b1e4aef395c0a1d56a28e69a4a17e',1,'vk_mem_alloc.h']]], + ['vmafreestatsstring_300',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], + ['vmagetallocationinfo_301',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], + ['vmagetallocatorinfo_302',['vmaGetAllocatorInfo',['../vk__mem__alloc_8h.html#afa02231a791b37255720d566a52683e7',1,'vk_mem_alloc.h']]], + ['vmagetbudget_303',['vmaGetBudget',['../vk__mem__alloc_8h.html#aec0ed24ebea2d0099eed5f801daaefba',1,'vk_mem_alloc.h']]], + ['vmagetmemoryproperties_304',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], + ['vmagetmemorytypeproperties_305',['vmaGetMemoryTypeProperties',['../vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], + ['vmagetphysicaldeviceproperties_306',['vmaGetPhysicalDeviceProperties',['../vk__mem__alloc_8h.html#aecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], + ['vmagetpoolname_307',['vmaGetPoolName',['../vk__mem__alloc_8h.html#af09b4e4eafdbee812e8d73ddf960f030',1,'vk_mem_alloc.h']]], + ['vmagetpoolstats_308',['vmaGetPoolStats',['../vk__mem__alloc_8h.html#ae8bf76997b234ef68aad922616df4153',1,'vk_mem_alloc.h']]], + ['vmainvalidateallocation_309',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#aaa8412919139ef413a4215ac6a290fae',1,'vk_mem_alloc.h']]], + ['vmainvalidateallocations_310',['vmaInvalidateAllocations',['../vk__mem__alloc_8h.html#ab25b558d75f7378ec944a1522fdcc3c5',1,'vk_mem_alloc.h']]], + ['vmamakepoolallocationslost_311',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]], + ['vmamapmemory_312',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], + ['vmasetallocationuserdata_313',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], + ['vmasetcurrentframeindex_314',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], + ['vmasetpoolname_315',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], + ['vmatouchallocation_316',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], + ['vmaunmapmemory_317',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js index ec06f8a..28631af 100644 --- a/docs/html/search/pages_0.js +++ b/docs/html/search/pages_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['allocation_20names_20and_20user_20data_489',['Allocation names and user data',['../allocation_annotation.html',1,'index']]] + ['allocation_20names_20and_20user_20data_491',['Allocation names and user data',['../allocation_annotation.html',1,'index']]] ]; diff --git a/docs/html/search/pages_1.js b/docs/html/search/pages_1.js index 1bbbe8a..fb0a6b2 100644 --- a/docs/html/search/pages_1.js +++ b/docs/html/search/pages_1.js @@ -1,6 +1,6 @@ var searchData= [ - ['choosing_20memory_20type_490',['Choosing memory type',['../choosing_memory_type.html',1,'index']]], - ['configuration_491',['Configuration',['../configuration.html',1,'index']]], - ['custom_20memory_20pools_492',['Custom memory pools',['../custom_memory_pools.html',1,'index']]] + ['choosing_20memory_20type_492',['Choosing memory type',['../choosing_memory_type.html',1,'index']]], + ['configuration_493',['Configuration',['../configuration.html',1,'index']]], + ['custom_20memory_20pools_494',['Custom memory pools',['../custom_memory_pools.html',1,'index']]] ]; diff --git a/docs/html/search/pages_2.js b/docs/html/search/pages_2.js index 41858fe..123b4c2 100644 --- a/docs/html/search/pages_2.js +++ b/docs/html/search/pages_2.js @@ -1,6 +1,6 @@ var searchData= [ - ['debugging_20incorrect_20memory_20usage_493',['Debugging incorrect memory usage',['../debugging_memory_usage.html',1,'index']]], - ['defragmentation_494',['Defragmentation',['../defragmentation.html',1,'index']]], - ['deprecated_20list_495',['Deprecated List',['../deprecated.html',1,'']]] + ['debugging_20incorrect_20memory_20usage_495',['Debugging incorrect memory usage',['../debugging_memory_usage.html',1,'index']]], + ['defragmentation_496',['Defragmentation',['../defragmentation.html',1,'index']]], + ['deprecated_20list_497',['Deprecated List',['../deprecated.html',1,'']]] ]; diff --git a/docs/html/search/pages_3.js b/docs/html/search/pages_3.js index 820e114..9cf7bed 100644 --- a/docs/html/search/pages_3.js +++ b/docs/html/search/pages_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['enabling_20buffer_20device_20address_496',['Enabling buffer device address',['../enabling_buffer_device_address.html',1,'index']]] + ['enabling_20buffer_20device_20address_498',['Enabling buffer device address',['../enabling_buffer_device_address.html',1,'index']]] ]; diff --git a/docs/html/search/pages_4.js b/docs/html/search/pages_4.js index f26eeca..abed90f 100644 --- a/docs/html/search/pages_4.js +++ b/docs/html/search/pages_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['general_20considerations_497',['General considerations',['../general_considerations.html',1,'index']]] + ['general_20considerations_499',['General considerations',['../general_considerations.html',1,'index']]] ]; diff --git a/docs/html/search/pages_5.js b/docs/html/search/pages_5.js index 6956b17..d8c6cb7 100644 --- a/docs/html/search/pages_5.js +++ b/docs/html/search/pages_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['lost_20allocations_498',['Lost allocations',['../lost_allocations.html',1,'index']]] + ['lost_20allocations_500',['Lost allocations',['../lost_allocations.html',1,'index']]] ]; diff --git a/docs/html/search/pages_6.js b/docs/html/search/pages_6.js index c517740..52995e2 100644 --- a/docs/html/search/pages_6.js +++ b/docs/html/search/pages_6.js @@ -1,4 +1,4 @@ var searchData= [ - ['memory_20mapping_499',['Memory mapping',['../memory_mapping.html',1,'index']]] + ['memory_20mapping_501',['Memory mapping',['../memory_mapping.html',1,'index']]] ]; diff --git a/docs/html/search/pages_7.js b/docs/html/search/pages_7.js index d3ca84e..73c2884 100644 --- a/docs/html/search/pages_7.js +++ b/docs/html/search/pages_7.js @@ -1,4 +1,4 @@ var searchData= [ - ['quick_20start_500',['Quick start',['../quick_start.html',1,'index']]] + ['quick_20start_502',['Quick start',['../quick_start.html',1,'index']]] ]; diff --git a/docs/html/search/pages_8.js b/docs/html/search/pages_8.js index 4c04e8b..889c4d4 100644 --- a/docs/html/search/pages_8.js +++ b/docs/html/search/pages_8.js @@ -1,6 +1,6 @@ var searchData= [ - ['recommended_20usage_20patterns_501',['Recommended usage patterns',['../usage_patterns.html',1,'index']]], - ['record_20and_20replay_502',['Record and replay',['../record_and_replay.html',1,'index']]], - ['resource_20aliasing_20_28overlap_29_503',['Resource aliasing (overlap)',['../resource_aliasing.html',1,'index']]] + ['recommended_20usage_20patterns_503',['Recommended usage patterns',['../usage_patterns.html',1,'index']]], + ['record_20and_20replay_504',['Record and replay',['../record_and_replay.html',1,'index']]], + ['resource_20aliasing_20_28overlap_29_505',['Resource aliasing (overlap)',['../resource_aliasing.html',1,'index']]] ]; diff --git a/docs/html/search/pages_9.js b/docs/html/search/pages_9.js index 13652d2..a2793e1 100644 --- a/docs/html/search/pages_9.js +++ b/docs/html/search/pages_9.js @@ -1,5 +1,5 @@ var searchData= [ - ['statistics_504',['Statistics',['../statistics.html',1,'index']]], - ['staying_20within_20budget_505',['Staying within budget',['../staying_within_budget.html',1,'index']]] + ['statistics_506',['Statistics',['../statistics.html',1,'index']]], + ['staying_20within_20budget_507',['Staying within budget',['../staying_within_budget.html',1,'index']]] ]; diff --git a/docs/html/search/pages_a.js b/docs/html/search/pages_a.js index 30ed0a1..807cf87 100644 --- a/docs/html/search/pages_a.js +++ b/docs/html/search/pages_a.js @@ -1,6 +1,6 @@ var searchData= [ - ['vk_5famd_5fdevice_5fcoherent_5fmemory_506',['VK_AMD_device_coherent_memory',['../vk_amd_device_coherent_memory.html',1,'index']]], - ['vk_5fkhr_5fdedicated_5fallocation_507',['VK_KHR_dedicated_allocation',['../vk_khr_dedicated_allocation.html',1,'index']]], - ['vulkan_20memory_20allocator_508',['Vulkan Memory Allocator',['../index.html',1,'']]] + ['vk_5famd_5fdevice_5fcoherent_5fmemory_508',['VK_AMD_device_coherent_memory',['../vk_amd_device_coherent_memory.html',1,'index']]], + ['vk_5fkhr_5fdedicated_5fallocation_509',['VK_KHR_dedicated_allocation',['../vk_khr_dedicated_allocation.html',1,'index']]], + ['vulkan_20memory_20allocator_510',['Vulkan Memory Allocator',['../index.html',1,'']]] ]; diff --git a/docs/html/search/typedefs_0.js b/docs/html/search/typedefs_0.js index c4d5a93..0755108 100644 --- a/docs/html/search/typedefs_0.js +++ b/docs/html/search/typedefs_0.js @@ -1,5 +1,5 @@ var searchData= [ - ['pfn_5fvmaallocatedevicememoryfunction_403',['PFN_vmaAllocateDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a7e1ed85f7799600b03ad51a77acc21f3',1,'vk_mem_alloc.h']]], - ['pfn_5fvmafreedevicememoryfunction_404',['PFN_vmaFreeDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a154ccaaf53dc2c36378f80f0c4f3679b',1,'vk_mem_alloc.h']]] + ['pfn_5fvmaallocatedevicememoryfunction_405',['PFN_vmaAllocateDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a7e1ed85f7799600b03ad51a77acc21f3',1,'vk_mem_alloc.h']]], + ['pfn_5fvmafreedevicememoryfunction_406',['PFN_vmaFreeDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a154ccaaf53dc2c36378f80f0c4f3679b',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/typedefs_1.js b/docs/html/search/typedefs_1.js index 3935cf7..3efcdcb 100644 --- a/docs/html/search/typedefs_1.js +++ b/docs/html/search/typedefs_1.js @@ -1,31 +1,31 @@ var searchData= [ - ['vmaallocationcreateflagbits_405',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#a4fceecc301f4064dc808d3cd6c038941',1,'vk_mem_alloc.h']]], - ['vmaallocationcreateflags_406',['VmaAllocationCreateFlags',['../vk__mem__alloc_8h.html#a5225e5e11f8376f6a31a1791f3d6e817',1,'vk_mem_alloc.h']]], - ['vmaallocationcreateinfo_407',['VmaAllocationCreateInfo',['../vk__mem__alloc_8h.html#a3bf110892ea2fb4649fedb68488d026a',1,'vk_mem_alloc.h']]], - ['vmaallocationinfo_408',['VmaAllocationInfo',['../vk__mem__alloc_8h.html#a1cf7774606721026a68aabe3af2e5b50',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateflagbits_409',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#afd73b95e737ee7e76f827cb5472f559f',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateflags_410',['VmaAllocatorCreateFlags',['../vk__mem__alloc_8h.html#acfe6863e160722c2c1bbcf7573fddc4d',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateinfo_411',['VmaAllocatorCreateInfo',['../vk__mem__alloc_8h.html#aad9652301d33759b83e52d4f3605a14a',1,'vk_mem_alloc.h']]], - ['vmaallocatorinfo_412',['VmaAllocatorInfo',['../vk__mem__alloc_8h.html#a1988031b0223fdbd564250fa1edd942c',1,'vk_mem_alloc.h']]], - ['vmabudget_413',['VmaBudget',['../vk__mem__alloc_8h.html#aa078667e71b1ef24e87a6a30d128381d',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflagbits_414',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a13415cc0b443353a7b5abda300b833fc',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflags_415',['VmaDefragmentationFlags',['../vk__mem__alloc_8h.html#a88a77cef37e5d3c4fc9eb328885d048d',1,'vk_mem_alloc.h']]], - ['vmadefragmentationinfo_416',['VmaDefragmentationInfo',['../vk__mem__alloc_8h.html#a2bf47f96bf92bed2a49461bd9af3acfa',1,'vk_mem_alloc.h']]], - ['vmadefragmentationinfo2_417',['VmaDefragmentationInfo2',['../vk__mem__alloc_8h.html#ad6daeffaa670ce6d11a203a6224c9937',1,'vk_mem_alloc.h']]], - ['vmadefragmentationpassinfo_418',['VmaDefragmentationPassInfo',['../vk__mem__alloc_8h.html#a72aebd522242d56abea67b4f47f6549e',1,'vk_mem_alloc.h']]], - ['vmadefragmentationpassmoveinfo_419',['VmaDefragmentationPassMoveInfo',['../vk__mem__alloc_8h.html#ad6799e8e2b1527abfc84d33bc44aeaf5',1,'vk_mem_alloc.h']]], - ['vmadefragmentationstats_420',['VmaDefragmentationStats',['../vk__mem__alloc_8h.html#ad94034192259c2e34a4d1c5e27810403',1,'vk_mem_alloc.h']]], - ['vmadevicememorycallbacks_421',['VmaDeviceMemoryCallbacks',['../vk__mem__alloc_8h.html#a77692d3c8770ea8882d573206bd27b2b',1,'vk_mem_alloc.h']]], - ['vmamemoryusage_422',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'vk_mem_alloc.h']]], - ['vmapoolcreateflagbits_423',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'vk_mem_alloc.h']]], - ['vmapoolcreateflags_424',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], - ['vmapoolcreateinfo_425',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'vk_mem_alloc.h']]], - ['vmapoolstats_426',['VmaPoolStats',['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'vk_mem_alloc.h']]], - ['vmarecordflagbits_427',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'vk_mem_alloc.h']]], - ['vmarecordflags_428',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], - ['vmarecordsettings_429',['VmaRecordSettings',['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'vk_mem_alloc.h']]], - ['vmastatinfo_430',['VmaStatInfo',['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'vk_mem_alloc.h']]], - ['vmastats_431',['VmaStats',['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'vk_mem_alloc.h']]], - ['vmavulkanfunctions_432',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'vk_mem_alloc.h']]] + ['vmaallocationcreateflagbits_407',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#a4fceecc301f4064dc808d3cd6c038941',1,'vk_mem_alloc.h']]], + ['vmaallocationcreateflags_408',['VmaAllocationCreateFlags',['../vk__mem__alloc_8h.html#a5225e5e11f8376f6a31a1791f3d6e817',1,'vk_mem_alloc.h']]], + ['vmaallocationcreateinfo_409',['VmaAllocationCreateInfo',['../vk__mem__alloc_8h.html#a3bf110892ea2fb4649fedb68488d026a',1,'vk_mem_alloc.h']]], + ['vmaallocationinfo_410',['VmaAllocationInfo',['../vk__mem__alloc_8h.html#a1cf7774606721026a68aabe3af2e5b50',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateflagbits_411',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#afd73b95e737ee7e76f827cb5472f559f',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateflags_412',['VmaAllocatorCreateFlags',['../vk__mem__alloc_8h.html#acfe6863e160722c2c1bbcf7573fddc4d',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateinfo_413',['VmaAllocatorCreateInfo',['../vk__mem__alloc_8h.html#aad9652301d33759b83e52d4f3605a14a',1,'vk_mem_alloc.h']]], + ['vmaallocatorinfo_414',['VmaAllocatorInfo',['../vk__mem__alloc_8h.html#a1988031b0223fdbd564250fa1edd942c',1,'vk_mem_alloc.h']]], + ['vmabudget_415',['VmaBudget',['../vk__mem__alloc_8h.html#aa078667e71b1ef24e87a6a30d128381d',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflagbits_416',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a13415cc0b443353a7b5abda300b833fc',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflags_417',['VmaDefragmentationFlags',['../vk__mem__alloc_8h.html#a88a77cef37e5d3c4fc9eb328885d048d',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo_418',['VmaDefragmentationInfo',['../vk__mem__alloc_8h.html#a2bf47f96bf92bed2a49461bd9af3acfa',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo2_419',['VmaDefragmentationInfo2',['../vk__mem__alloc_8h.html#ad6daeffaa670ce6d11a203a6224c9937',1,'vk_mem_alloc.h']]], + ['vmadefragmentationpassinfo_420',['VmaDefragmentationPassInfo',['../vk__mem__alloc_8h.html#a72aebd522242d56abea67b4f47f6549e',1,'vk_mem_alloc.h']]], + ['vmadefragmentationpassmoveinfo_421',['VmaDefragmentationPassMoveInfo',['../vk__mem__alloc_8h.html#ad6799e8e2b1527abfc84d33bc44aeaf5',1,'vk_mem_alloc.h']]], + ['vmadefragmentationstats_422',['VmaDefragmentationStats',['../vk__mem__alloc_8h.html#ad94034192259c2e34a4d1c5e27810403',1,'vk_mem_alloc.h']]], + ['vmadevicememorycallbacks_423',['VmaDeviceMemoryCallbacks',['../vk__mem__alloc_8h.html#a77692d3c8770ea8882d573206bd27b2b',1,'vk_mem_alloc.h']]], + ['vmamemoryusage_424',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'vk_mem_alloc.h']]], + ['vmapoolcreateflagbits_425',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'vk_mem_alloc.h']]], + ['vmapoolcreateflags_426',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], + ['vmapoolcreateinfo_427',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'vk_mem_alloc.h']]], + ['vmapoolstats_428',['VmaPoolStats',['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'vk_mem_alloc.h']]], + ['vmarecordflagbits_429',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'vk_mem_alloc.h']]], + ['vmarecordflags_430',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], + ['vmarecordsettings_431',['VmaRecordSettings',['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'vk_mem_alloc.h']]], + ['vmastatinfo_432',['VmaStatInfo',['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'vk_mem_alloc.h']]], + ['vmastats_433',['VmaStats',['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'vk_mem_alloc.h']]], + ['vmavulkanfunctions_434',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/variables_0.js b/docs/html/search/variables_0.js index e599d0d..41b250a 100644 --- a/docs/html/search/variables_0.js +++ b/docs/html/search/variables_0.js @@ -1,10 +1,10 @@ var searchData= [ - ['allocation_316',['allocation',['../struct_vma_defragmentation_pass_move_info.html#ae885c861c2dd8d622e6c19e281d035cc',1,'VmaDefragmentationPassMoveInfo']]], - ['allocationbytes_317',['allocationBytes',['../struct_vma_budget.html#a7e2a6583ebd63e194951c542563804d8',1,'VmaBudget']]], - ['allocationcount_318',['allocationCount',['../struct_vma_stat_info.html#a537741e4d5cdddc1c0ab95ec650afaff',1,'VmaStatInfo::allocationCount()'],['../struct_vma_pool_stats.html#ad1924eb54fffa45e9e0e65670c8fe5eb',1,'VmaPoolStats::allocationCount()'],['../struct_vma_defragmentation_info2.html#a3cf86ab32c1da779b4923d301a3056ba',1,'VmaDefragmentationInfo2::allocationCount()']]], - ['allocationsizeavg_319',['allocationSizeAvg',['../struct_vma_stat_info.html#a1081a039964e566c672e7a2347f9e599',1,'VmaStatInfo']]], - ['allocationsizemax_320',['allocationSizeMax',['../struct_vma_stat_info.html#a17e9733a5ecd76287d4db6e66f71f50c',1,'VmaStatInfo']]], - ['allocationsizemin_321',['allocationSizeMin',['../struct_vma_stat_info.html#ade8b40bd3139c04aabd2fc538a356fea',1,'VmaStatInfo']]], - ['allocationsmoved_322',['allocationsMoved',['../struct_vma_defragmentation_stats.html#aefeabf130022008eadd75999478af3f9',1,'VmaDefragmentationStats']]] + ['allocation_318',['allocation',['../struct_vma_defragmentation_pass_move_info.html#ae885c861c2dd8d622e6c19e281d035cc',1,'VmaDefragmentationPassMoveInfo']]], + ['allocationbytes_319',['allocationBytes',['../struct_vma_budget.html#a7e2a6583ebd63e194951c542563804d8',1,'VmaBudget']]], + ['allocationcount_320',['allocationCount',['../struct_vma_stat_info.html#a537741e4d5cdddc1c0ab95ec650afaff',1,'VmaStatInfo::allocationCount()'],['../struct_vma_pool_stats.html#ad1924eb54fffa45e9e0e65670c8fe5eb',1,'VmaPoolStats::allocationCount()'],['../struct_vma_defragmentation_info2.html#a3cf86ab32c1da779b4923d301a3056ba',1,'VmaDefragmentationInfo2::allocationCount()']]], + ['allocationsizeavg_321',['allocationSizeAvg',['../struct_vma_stat_info.html#a1081a039964e566c672e7a2347f9e599',1,'VmaStatInfo']]], + ['allocationsizemax_322',['allocationSizeMax',['../struct_vma_stat_info.html#a17e9733a5ecd76287d4db6e66f71f50c',1,'VmaStatInfo']]], + ['allocationsizemin_323',['allocationSizeMin',['../struct_vma_stat_info.html#ade8b40bd3139c04aabd2fc538a356fea',1,'VmaStatInfo']]], + ['allocationsmoved_324',['allocationsMoved',['../struct_vma_defragmentation_stats.html#aefeabf130022008eadd75999478af3f9',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_1.js b/docs/html/search/variables_1.js index fca9725..3fcb665 100644 --- a/docs/html/search/variables_1.js +++ b/docs/html/search/variables_1.js @@ -1,9 +1,9 @@ var searchData= [ - ['blockbytes_323',['blockBytes',['../struct_vma_budget.html#a58b492901baab685f466199124e514a0',1,'VmaBudget']]], - ['blockcount_324',['blockCount',['../struct_vma_stat_info.html#abc4bb7cd611900778464c56e50c970a4',1,'VmaStatInfo::blockCount()'],['../struct_vma_pool_stats.html#aa0b5cb45cef6f18571cefb03b9a230e7',1,'VmaPoolStats::blockCount()']]], - ['blocksize_325',['blockSize',['../struct_vma_pool_create_info.html#aa4265160536cdb9be821b7686c16c676',1,'VmaPoolCreateInfo']]], - ['budget_326',['budget',['../struct_vma_budget.html#ab82e1d1754c2d210d0bdf90220bc6cdd',1,'VmaBudget']]], - ['bytesfreed_327',['bytesFreed',['../struct_vma_defragmentation_stats.html#ab0cb9ac0dbc106c77e384ea676422f28',1,'VmaDefragmentationStats']]], - ['bytesmoved_328',['bytesMoved',['../struct_vma_defragmentation_stats.html#a36f9d5df2a10ba2a36b16e126d60572d',1,'VmaDefragmentationStats']]] + ['blockbytes_325',['blockBytes',['../struct_vma_budget.html#a58b492901baab685f466199124e514a0',1,'VmaBudget']]], + ['blockcount_326',['blockCount',['../struct_vma_stat_info.html#abc4bb7cd611900778464c56e50c970a4',1,'VmaStatInfo::blockCount()'],['../struct_vma_pool_stats.html#aa0b5cb45cef6f18571cefb03b9a230e7',1,'VmaPoolStats::blockCount()']]], + ['blocksize_327',['blockSize',['../struct_vma_pool_create_info.html#aa4265160536cdb9be821b7686c16c676',1,'VmaPoolCreateInfo']]], + ['budget_328',['budget',['../struct_vma_budget.html#ab82e1d1754c2d210d0bdf90220bc6cdd',1,'VmaBudget']]], + ['bytesfreed_329',['bytesFreed',['../struct_vma_defragmentation_stats.html#ab0cb9ac0dbc106c77e384ea676422f28',1,'VmaDefragmentationStats']]], + ['bytesmoved_330',['bytesMoved',['../struct_vma_defragmentation_stats.html#a36f9d5df2a10ba2a36b16e126d60572d',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_2.js b/docs/html/search/variables_2.js index d8caf40..328a2c8 100644 --- a/docs/html/search/variables_2.js +++ b/docs/html/search/variables_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['commandbuffer_329',['commandBuffer',['../struct_vma_defragmentation_info2.html#a7f71f39590c5316771493d2333f9c1bd',1,'VmaDefragmentationInfo2']]] + ['commandbuffer_331',['commandBuffer',['../struct_vma_defragmentation_info2.html#a7f71f39590c5316771493d2333f9c1bd',1,'VmaDefragmentationInfo2']]] ]; diff --git a/docs/html/search/variables_3.js b/docs/html/search/variables_3.js index a924c83..0878b75 100644 --- a/docs/html/search/variables_3.js +++ b/docs/html/search/variables_3.js @@ -1,6 +1,6 @@ var searchData= [ - ['device_330',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo::device()'],['../struct_vma_allocator_info.html#a012b4c485bf3b0ea8921352c5ee0c357',1,'VmaAllocatorInfo::device()']]], - ['devicememory_331',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], - ['devicememoryblocksfreed_332',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]] + ['device_332',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo::device()'],['../struct_vma_allocator_info.html#a012b4c485bf3b0ea8921352c5ee0c357',1,'VmaAllocatorInfo::device()']]], + ['devicememory_333',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], + ['devicememoryblocksfreed_334',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_4.js b/docs/html/search/variables_4.js index e2744ed..7214e6b 100644 --- a/docs/html/search/variables_4.js +++ b/docs/html/search/variables_4.js @@ -1,5 +1,5 @@ var searchData= [ - ['flags_333',['flags',['../struct_vma_record_settings.html#ad8fdcc92119ae7a8c08c1a564c01d63a',1,'VmaRecordSettings::flags()'],['../struct_vma_allocator_create_info.html#a392ea2ecbaff93f91a7c49f735ad4346',1,'VmaAllocatorCreateInfo::flags()'],['../struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b',1,'VmaAllocationCreateInfo::flags()'],['../struct_vma_pool_create_info.html#a8405139f63d078340ae74513a59f5446',1,'VmaPoolCreateInfo::flags()'],['../struct_vma_defragmentation_info2.html#a53e844ee5633e229cf6daf14b2d9fff9',1,'VmaDefragmentationInfo2::flags()']]], - ['frameinusecount_334',['frameInUseCount',['../struct_vma_allocator_create_info.html#a21ea188dd212b8171cb9ecbed4a2a3a7',1,'VmaAllocatorCreateInfo::frameInUseCount()'],['../struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa',1,'VmaPoolCreateInfo::frameInUseCount()']]] + ['flags_335',['flags',['../struct_vma_record_settings.html#ad8fdcc92119ae7a8c08c1a564c01d63a',1,'VmaRecordSettings::flags()'],['../struct_vma_allocator_create_info.html#a392ea2ecbaff93f91a7c49f735ad4346',1,'VmaAllocatorCreateInfo::flags()'],['../struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b',1,'VmaAllocationCreateInfo::flags()'],['../struct_vma_pool_create_info.html#a8405139f63d078340ae74513a59f5446',1,'VmaPoolCreateInfo::flags()'],['../struct_vma_defragmentation_info2.html#a53e844ee5633e229cf6daf14b2d9fff9',1,'VmaDefragmentationInfo2::flags()']]], + ['frameinusecount_336',['frameInUseCount',['../struct_vma_allocator_create_info.html#a21ea188dd212b8171cb9ecbed4a2a3a7',1,'VmaAllocatorCreateInfo::frameInUseCount()'],['../struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa',1,'VmaPoolCreateInfo::frameInUseCount()']]] ]; diff --git a/docs/html/search/variables_5.js b/docs/html/search/variables_5.js index f6ac8c9..e371dd9 100644 --- a/docs/html/search/variables_5.js +++ b/docs/html/search/variables_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['instance_335',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]] + ['instance_337',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]] ]; diff --git a/docs/html/search/variables_6.js b/docs/html/search/variables_6.js index 01ba82a..a62809d 100644 --- a/docs/html/search/variables_6.js +++ b/docs/html/search/variables_6.js @@ -1,18 +1,18 @@ var searchData= [ - ['maxallocationstomove_336',['maxAllocationsToMove',['../struct_vma_defragmentation_info.html#aa7c7304e13c71f604c907196c4e28fbc',1,'VmaDefragmentationInfo']]], - ['maxblockcount_337',['maxBlockCount',['../struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c',1,'VmaPoolCreateInfo']]], - ['maxbytestomove_338',['maxBytesToMove',['../struct_vma_defragmentation_info.html#acb311c940a777270e67e1b81c5ab6a1d',1,'VmaDefragmentationInfo']]], - ['maxcpuallocationstomove_339',['maxCpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a94c2c7223d52878445a8cccce396b671',1,'VmaDefragmentationInfo2']]], - ['maxcpubytestomove_340',['maxCpuBytesToMove',['../struct_vma_defragmentation_info2.html#af78e1ea40c22d85137b65f6b384a4d0a',1,'VmaDefragmentationInfo2']]], - ['maxgpuallocationstomove_341',['maxGpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a40d53d33e71ba0b66f844ed63c05a3f6',1,'VmaDefragmentationInfo2']]], - ['maxgpubytestomove_342',['maxGpuBytesToMove',['../struct_vma_defragmentation_info2.html#a4ddbc898d0afe1518f863a3763628f08',1,'VmaDefragmentationInfo2']]], - ['memory_343',['memory',['../struct_vma_defragmentation_pass_move_info.html#a06eb0c8690aa0d3478a036753492e769',1,'VmaDefragmentationPassMoveInfo']]], - ['memoryheap_344',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], - ['memorytype_345',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats::memoryType()'],['../struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5',1,'VmaAllocationInfo::memoryType()']]], - ['memorytypebits_346',['memoryTypeBits',['../struct_vma_allocation_create_info.html#a3bf940c0271d85d6ba32a4d820075055',1,'VmaAllocationCreateInfo']]], - ['memorytypeindex_347',['memoryTypeIndex',['../struct_vma_pool_create_info.html#a596fa76b685d3f1f688f84a709a5b319',1,'VmaPoolCreateInfo']]], - ['minallocationalignment_348',['minAllocationAlignment',['../struct_vma_pool_create_info.html#ade3eca546f0c6ab4e8fbf20eb6d854cb',1,'VmaPoolCreateInfo']]], - ['minblockcount_349',['minBlockCount',['../struct_vma_pool_create_info.html#ad8006fb803185c0a699d30f3e9a865ae',1,'VmaPoolCreateInfo']]], - ['movecount_350',['moveCount',['../struct_vma_defragmentation_pass_info.html#ac1086e657ba995f8d1f4e49b83dcfb6c',1,'VmaDefragmentationPassInfo']]] + ['maxallocationstomove_338',['maxAllocationsToMove',['../struct_vma_defragmentation_info.html#aa7c7304e13c71f604c907196c4e28fbc',1,'VmaDefragmentationInfo']]], + ['maxblockcount_339',['maxBlockCount',['../struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c',1,'VmaPoolCreateInfo']]], + ['maxbytestomove_340',['maxBytesToMove',['../struct_vma_defragmentation_info.html#acb311c940a777270e67e1b81c5ab6a1d',1,'VmaDefragmentationInfo']]], + ['maxcpuallocationstomove_341',['maxCpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a94c2c7223d52878445a8cccce396b671',1,'VmaDefragmentationInfo2']]], + ['maxcpubytestomove_342',['maxCpuBytesToMove',['../struct_vma_defragmentation_info2.html#af78e1ea40c22d85137b65f6b384a4d0a',1,'VmaDefragmentationInfo2']]], + ['maxgpuallocationstomove_343',['maxGpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a40d53d33e71ba0b66f844ed63c05a3f6',1,'VmaDefragmentationInfo2']]], + ['maxgpubytestomove_344',['maxGpuBytesToMove',['../struct_vma_defragmentation_info2.html#a4ddbc898d0afe1518f863a3763628f08',1,'VmaDefragmentationInfo2']]], + ['memory_345',['memory',['../struct_vma_defragmentation_pass_move_info.html#a06eb0c8690aa0d3478a036753492e769',1,'VmaDefragmentationPassMoveInfo']]], + ['memoryheap_346',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], + ['memorytype_347',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats::memoryType()'],['../struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5',1,'VmaAllocationInfo::memoryType()']]], + ['memorytypebits_348',['memoryTypeBits',['../struct_vma_allocation_create_info.html#a3bf940c0271d85d6ba32a4d820075055',1,'VmaAllocationCreateInfo']]], + ['memorytypeindex_349',['memoryTypeIndex',['../struct_vma_pool_create_info.html#a596fa76b685d3f1f688f84a709a5b319',1,'VmaPoolCreateInfo']]], + ['minallocationalignment_350',['minAllocationAlignment',['../struct_vma_pool_create_info.html#ade3eca546f0c6ab4e8fbf20eb6d854cb',1,'VmaPoolCreateInfo']]], + ['minblockcount_351',['minBlockCount',['../struct_vma_pool_create_info.html#ad8006fb803185c0a699d30f3e9a865ae',1,'VmaPoolCreateInfo']]], + ['movecount_352',['moveCount',['../struct_vma_defragmentation_pass_info.html#ac1086e657ba995f8d1f4e49b83dcfb6c',1,'VmaDefragmentationPassInfo']]] ]; diff --git a/docs/html/search/variables_7.js b/docs/html/search/variables_7.js index ff83f00..cee1168 100644 --- a/docs/html/search/variables_7.js +++ b/docs/html/search/variables_7.js @@ -1,4 +1,4 @@ var searchData= [ - ['offset_351',['offset',['../struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268',1,'VmaAllocationInfo::offset()'],['../struct_vma_defragmentation_pass_move_info.html#a8ab4508bc03625b0653c880576be96c6',1,'VmaDefragmentationPassMoveInfo::offset()']]] + ['offset_353',['offset',['../struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268',1,'VmaAllocationInfo::offset()'],['../struct_vma_defragmentation_pass_move_info.html#a8ab4508bc03625b0653c880576be96c6',1,'VmaDefragmentationPassMoveInfo::offset()']]] ]; diff --git a/docs/html/search/variables_8.js b/docs/html/search/variables_8.js index 4b36d49..25dc99b 100644 --- a/docs/html/search/variables_8.js +++ b/docs/html/search/variables_8.js @@ -1,25 +1,25 @@ var searchData= [ - ['pallocationcallbacks_352',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], - ['pallocations_353',['pAllocations',['../struct_vma_defragmentation_info2.html#ab6d288f29d028156cf73542d630a2e32',1,'VmaDefragmentationInfo2']]], - ['pallocationschanged_354',['pAllocationsChanged',['../struct_vma_defragmentation_info2.html#a76d51a644dc7f5405d0cdd0025ecd0cc',1,'VmaDefragmentationInfo2']]], - ['pdevicememorycallbacks_355',['pDeviceMemoryCallbacks',['../struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e',1,'VmaAllocatorCreateInfo']]], - ['pfilepath_356',['pFilePath',['../struct_vma_record_settings.html#a6cb1fdbf6bcb610b68f2010dd629e89d',1,'VmaRecordSettings']]], - ['pfnallocate_357',['pfnAllocate',['../struct_vma_device_memory_callbacks.html#a4f17f7b255101e733b44d5633aceabfb',1,'VmaDeviceMemoryCallbacks']]], - ['pfnfree_358',['pfnFree',['../struct_vma_device_memory_callbacks.html#abe8a3328bbc916f6f712fdb6b299444c',1,'VmaDeviceMemoryCallbacks']]], - ['pheapsizelimit_359',['pHeapSizeLimit',['../struct_vma_allocator_create_info.html#a31c192aa6cbffa33279f6d9f0c47c44b',1,'VmaAllocatorCreateInfo']]], - ['physicaldevice_360',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo::physicalDevice()'],['../struct_vma_allocator_info.html#aba2b703f96e51d567717e1fb2935b47a',1,'VmaAllocatorInfo::physicalDevice()']]], - ['pmappeddata_361',['pMappedData',['../struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2',1,'VmaAllocationInfo']]], - ['pmemoryallocatenext_362',['pMemoryAllocateNext',['../struct_vma_pool_create_info.html#af0f8c58f51a2a7a0a389dc79565044d7',1,'VmaPoolCreateInfo']]], - ['pmoves_363',['pMoves',['../struct_vma_defragmentation_pass_info.html#acbd42d4a3357999da130a95cd99a3792',1,'VmaDefragmentationPassInfo']]], - ['pool_364',['pool',['../struct_vma_allocation_create_info.html#a6272c0555cfd1fe28bff1afeb6190150',1,'VmaAllocationCreateInfo']]], - ['poolcount_365',['poolCount',['../struct_vma_defragmentation_info2.html#a7e70aa2a1081d849dcc7829b19d3ec9d',1,'VmaDefragmentationInfo2']]], - ['ppools_366',['pPools',['../struct_vma_defragmentation_info2.html#a3c9c6aa5c97d5670f8e362b3a6f3029b',1,'VmaDefragmentationInfo2']]], - ['precordsettings_367',['pRecordSettings',['../struct_vma_allocator_create_info.html#ace2aa4877b16a42b0b7673d4e26000ee',1,'VmaAllocatorCreateInfo']]], - ['preferredflags_368',['preferredFlags',['../struct_vma_allocation_create_info.html#a7fe8d81a1ad10b2a2faacacee5b15d6d',1,'VmaAllocationCreateInfo']]], - ['preferredlargeheapblocksize_369',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], - ['priority_370',['priority',['../struct_vma_allocation_create_info.html#a983d39e1a2e63649d78a960aa2fdd0f7',1,'VmaAllocationCreateInfo::priority()'],['../struct_vma_pool_create_info.html#a16e686c688f6725f119ebf6e24ab5274',1,'VmaPoolCreateInfo::priority()']]], - ['ptypeexternalmemoryhandletypes_371',['pTypeExternalMemoryHandleTypes',['../struct_vma_allocator_create_info.html#ae8f0db05e5cb4c43d7713bf4a49a736b',1,'VmaAllocatorCreateInfo']]], - ['puserdata_372',['pUserData',['../struct_vma_device_memory_callbacks.html#a24052de0937ddd54015a2df0363903c6',1,'VmaDeviceMemoryCallbacks::pUserData()'],['../struct_vma_allocation_create_info.html#a8259e85c272683434f4abb4ddddffe19',1,'VmaAllocationCreateInfo::pUserData()'],['../struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13',1,'VmaAllocationInfo::pUserData()']]], - ['pvulkanfunctions_373',['pVulkanFunctions',['../struct_vma_allocator_create_info.html#a3dc197be3227da7338b1643f70db36bd',1,'VmaAllocatorCreateInfo']]] + ['pallocationcallbacks_354',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], + ['pallocations_355',['pAllocations',['../struct_vma_defragmentation_info2.html#ab6d288f29d028156cf73542d630a2e32',1,'VmaDefragmentationInfo2']]], + ['pallocationschanged_356',['pAllocationsChanged',['../struct_vma_defragmentation_info2.html#a76d51a644dc7f5405d0cdd0025ecd0cc',1,'VmaDefragmentationInfo2']]], + ['pdevicememorycallbacks_357',['pDeviceMemoryCallbacks',['../struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e',1,'VmaAllocatorCreateInfo']]], + ['pfilepath_358',['pFilePath',['../struct_vma_record_settings.html#a6cb1fdbf6bcb610b68f2010dd629e89d',1,'VmaRecordSettings']]], + ['pfnallocate_359',['pfnAllocate',['../struct_vma_device_memory_callbacks.html#a4f17f7b255101e733b44d5633aceabfb',1,'VmaDeviceMemoryCallbacks']]], + ['pfnfree_360',['pfnFree',['../struct_vma_device_memory_callbacks.html#abe8a3328bbc916f6f712fdb6b299444c',1,'VmaDeviceMemoryCallbacks']]], + ['pheapsizelimit_361',['pHeapSizeLimit',['../struct_vma_allocator_create_info.html#a31c192aa6cbffa33279f6d9f0c47c44b',1,'VmaAllocatorCreateInfo']]], + ['physicaldevice_362',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo::physicalDevice()'],['../struct_vma_allocator_info.html#aba2b703f96e51d567717e1fb2935b47a',1,'VmaAllocatorInfo::physicalDevice()']]], + ['pmappeddata_363',['pMappedData',['../struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2',1,'VmaAllocationInfo']]], + ['pmemoryallocatenext_364',['pMemoryAllocateNext',['../struct_vma_pool_create_info.html#af0f8c58f51a2a7a0a389dc79565044d7',1,'VmaPoolCreateInfo']]], + ['pmoves_365',['pMoves',['../struct_vma_defragmentation_pass_info.html#acbd42d4a3357999da130a95cd99a3792',1,'VmaDefragmentationPassInfo']]], + ['pool_366',['pool',['../struct_vma_allocation_create_info.html#a6272c0555cfd1fe28bff1afeb6190150',1,'VmaAllocationCreateInfo']]], + ['poolcount_367',['poolCount',['../struct_vma_defragmentation_info2.html#a7e70aa2a1081d849dcc7829b19d3ec9d',1,'VmaDefragmentationInfo2']]], + ['ppools_368',['pPools',['../struct_vma_defragmentation_info2.html#a3c9c6aa5c97d5670f8e362b3a6f3029b',1,'VmaDefragmentationInfo2']]], + ['precordsettings_369',['pRecordSettings',['../struct_vma_allocator_create_info.html#ace2aa4877b16a42b0b7673d4e26000ee',1,'VmaAllocatorCreateInfo']]], + ['preferredflags_370',['preferredFlags',['../struct_vma_allocation_create_info.html#a7fe8d81a1ad10b2a2faacacee5b15d6d',1,'VmaAllocationCreateInfo']]], + ['preferredlargeheapblocksize_371',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], + ['priority_372',['priority',['../struct_vma_allocation_create_info.html#a983d39e1a2e63649d78a960aa2fdd0f7',1,'VmaAllocationCreateInfo::priority()'],['../struct_vma_pool_create_info.html#a16e686c688f6725f119ebf6e24ab5274',1,'VmaPoolCreateInfo::priority()']]], + ['ptypeexternalmemoryhandletypes_373',['pTypeExternalMemoryHandleTypes',['../struct_vma_allocator_create_info.html#ae8f0db05e5cb4c43d7713bf4a49a736b',1,'VmaAllocatorCreateInfo']]], + ['puserdata_374',['pUserData',['../struct_vma_device_memory_callbacks.html#a24052de0937ddd54015a2df0363903c6',1,'VmaDeviceMemoryCallbacks::pUserData()'],['../struct_vma_allocation_create_info.html#a8259e85c272683434f4abb4ddddffe19',1,'VmaAllocationCreateInfo::pUserData()'],['../struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13',1,'VmaAllocationInfo::pUserData()']]], + ['pvulkanfunctions_375',['pVulkanFunctions',['../struct_vma_allocator_create_info.html#a3dc197be3227da7338b1643f70db36bd',1,'VmaAllocatorCreateInfo']]] ]; diff --git a/docs/html/search/variables_9.js b/docs/html/search/variables_9.js index 914b13a..c04c7d6 100644 --- a/docs/html/search/variables_9.js +++ b/docs/html/search/variables_9.js @@ -1,4 +1,4 @@ var searchData= [ - ['requiredflags_374',['requiredFlags',['../struct_vma_allocation_create_info.html#a9166390303ff42d783305bc31c2b6b90',1,'VmaAllocationCreateInfo']]] + ['requiredflags_376',['requiredFlags',['../struct_vma_allocation_create_info.html#a9166390303ff42d783305bc31c2b6b90',1,'VmaAllocationCreateInfo']]] ]; diff --git a/docs/html/search/variables_a.js b/docs/html/search/variables_a.js index 348b07c..b87b500 100644 --- a/docs/html/search/variables_a.js +++ b/docs/html/search/variables_a.js @@ -1,4 +1,4 @@ var searchData= [ - ['size_375',['size',['../struct_vma_pool_stats.html#a326807b2de2b0931cee4ed9a5f2e420c',1,'VmaPoolStats::size()'],['../struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f',1,'VmaAllocationInfo::size()']]] + ['size_377',['size',['../struct_vma_pool_stats.html#a326807b2de2b0931cee4ed9a5f2e420c',1,'VmaPoolStats::size()'],['../struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f',1,'VmaAllocationInfo::size()']]] ]; diff --git a/docs/html/search/variables_b.js b/docs/html/search/variables_b.js index 77ec7d9..20700ba 100644 --- a/docs/html/search/variables_b.js +++ b/docs/html/search/variables_b.js @@ -1,4 +1,4 @@ var searchData= [ - ['total_376',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] + ['total_378',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] ]; diff --git a/docs/html/search/variables_c.js b/docs/html/search/variables_c.js index e3714b4..300c0cf 100644 --- a/docs/html/search/variables_c.js +++ b/docs/html/search/variables_c.js @@ -1,11 +1,11 @@ var searchData= [ - ['unusedbytes_377',['unusedBytes',['../struct_vma_stat_info.html#a1859d290aca2cd582d8dc25922092669',1,'VmaStatInfo']]], - ['unusedrangecount_378',['unusedRangeCount',['../struct_vma_stat_info.html#ae06129c771bfebfd6468a7f4276502a9',1,'VmaStatInfo::unusedRangeCount()'],['../struct_vma_pool_stats.html#ae4f3546ffa4d1e598b64d8e6134854f4',1,'VmaPoolStats::unusedRangeCount()']]], - ['unusedrangesizeavg_379',['unusedRangeSizeAvg',['../struct_vma_stat_info.html#a2f9b3452af90c9768a30b7fb6ae194fc',1,'VmaStatInfo']]], - ['unusedrangesizemax_380',['unusedRangeSizeMax',['../struct_vma_stat_info.html#a5ba1a2476c4d39b10f7e2f7ebbb72ac4',1,'VmaStatInfo::unusedRangeSizeMax()'],['../struct_vma_pool_stats.html#ab4c8f52dd42ab01998f60f0b6acc722b',1,'VmaPoolStats::unusedRangeSizeMax()']]], - ['unusedrangesizemin_381',['unusedRangeSizeMin',['../struct_vma_stat_info.html#aedeba931324f16589cd2416c0d2dd0d4',1,'VmaStatInfo']]], - ['unusedsize_382',['unusedSize',['../struct_vma_pool_stats.html#ad7c54874724fce7b06aba526202d82a8',1,'VmaPoolStats']]], - ['usage_383',['usage',['../struct_vma_budget.html#a84dd1ecca8b0110259eb206dbadb11f6',1,'VmaBudget::usage()'],['../struct_vma_allocation_create_info.html#accb8b06b1f677d858cb9af20705fa910',1,'VmaAllocationCreateInfo::usage()']]], - ['usedbytes_384',['usedBytes',['../struct_vma_stat_info.html#ab0c6c73837e5a70c749fbd4f6064895a',1,'VmaStatInfo']]] + ['unusedbytes_379',['unusedBytes',['../struct_vma_stat_info.html#a1859d290aca2cd582d8dc25922092669',1,'VmaStatInfo']]], + ['unusedrangecount_380',['unusedRangeCount',['../struct_vma_stat_info.html#ae06129c771bfebfd6468a7f4276502a9',1,'VmaStatInfo::unusedRangeCount()'],['../struct_vma_pool_stats.html#ae4f3546ffa4d1e598b64d8e6134854f4',1,'VmaPoolStats::unusedRangeCount()']]], + ['unusedrangesizeavg_381',['unusedRangeSizeAvg',['../struct_vma_stat_info.html#a2f9b3452af90c9768a30b7fb6ae194fc',1,'VmaStatInfo']]], + ['unusedrangesizemax_382',['unusedRangeSizeMax',['../struct_vma_stat_info.html#a5ba1a2476c4d39b10f7e2f7ebbb72ac4',1,'VmaStatInfo::unusedRangeSizeMax()'],['../struct_vma_pool_stats.html#ab4c8f52dd42ab01998f60f0b6acc722b',1,'VmaPoolStats::unusedRangeSizeMax()']]], + ['unusedrangesizemin_383',['unusedRangeSizeMin',['../struct_vma_stat_info.html#aedeba931324f16589cd2416c0d2dd0d4',1,'VmaStatInfo']]], + ['unusedsize_384',['unusedSize',['../struct_vma_pool_stats.html#ad7c54874724fce7b06aba526202d82a8',1,'VmaPoolStats']]], + ['usage_385',['usage',['../struct_vma_budget.html#a84dd1ecca8b0110259eb206dbadb11f6',1,'VmaBudget::usage()'],['../struct_vma_allocation_create_info.html#accb8b06b1f677d858cb9af20705fa910',1,'VmaAllocationCreateInfo::usage()']]], + ['usedbytes_386',['usedBytes',['../struct_vma_stat_info.html#ab0c6c73837e5a70c749fbd4f6064895a',1,'VmaStatInfo']]] ]; diff --git a/docs/html/search/variables_d.js b/docs/html/search/variables_d.js index 8f3e9f6..60ff9d5 100644 --- a/docs/html/search/variables_d.js +++ b/docs/html/search/variables_d.js @@ -1,21 +1,21 @@ var searchData= [ - ['vkallocatememory_385',['vkAllocateMemory',['../struct_vma_vulkan_functions.html#a2943bf99dfd784a0e8f599d987e22e6c',1,'VmaVulkanFunctions']]], - ['vkbindbuffermemory_386',['vkBindBufferMemory',['../struct_vma_vulkan_functions.html#a94fc4f3a605d9880bb3c0ba2c2fc80b2',1,'VmaVulkanFunctions']]], - ['vkbindimagememory_387',['vkBindImageMemory',['../struct_vma_vulkan_functions.html#a1338d96a128a5ade648b8d934907c637',1,'VmaVulkanFunctions']]], - ['vkcmdcopybuffer_388',['vkCmdCopyBuffer',['../struct_vma_vulkan_functions.html#ae5c0db8c89a3b82593dc16aa6a49fa3a',1,'VmaVulkanFunctions']]], - ['vkcreatebuffer_389',['vkCreateBuffer',['../struct_vma_vulkan_functions.html#ae8084315a25006271a2edfc3a447519f',1,'VmaVulkanFunctions']]], - ['vkcreateimage_390',['vkCreateImage',['../struct_vma_vulkan_functions.html#a23ebe70be515b9b5010a1d691200e325',1,'VmaVulkanFunctions']]], - ['vkdestroybuffer_391',['vkDestroyBuffer',['../struct_vma_vulkan_functions.html#a7e054606faddb07f0e8556f3ed317d45',1,'VmaVulkanFunctions']]], - ['vkdestroyimage_392',['vkDestroyImage',['../struct_vma_vulkan_functions.html#a90b898227039b1dcb3520f6e91f09ffa',1,'VmaVulkanFunctions']]], - ['vkflushmappedmemoryranges_393',['vkFlushMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a33c322f4c4ad2810f8a9c97a277572f9',1,'VmaVulkanFunctions']]], - ['vkfreememory_394',['vkFreeMemory',['../struct_vma_vulkan_functions.html#a4c658701778564d62034255b5dda91b4',1,'VmaVulkanFunctions']]], - ['vkgetbuffermemoryrequirements_395',['vkGetBufferMemoryRequirements',['../struct_vma_vulkan_functions.html#a5b92901df89a4194b0d12f6071d4d143',1,'VmaVulkanFunctions']]], - ['vkgetimagememoryrequirements_396',['vkGetImageMemoryRequirements',['../struct_vma_vulkan_functions.html#a475f6f49f8debe4d10800592606d53f4',1,'VmaVulkanFunctions']]], - ['vkgetphysicaldevicememoryproperties_397',['vkGetPhysicalDeviceMemoryProperties',['../struct_vma_vulkan_functions.html#a60d25c33bba06bb8592e6875cbaa9830',1,'VmaVulkanFunctions']]], - ['vkgetphysicaldeviceproperties_398',['vkGetPhysicalDeviceProperties',['../struct_vma_vulkan_functions.html#a77b7a74082823e865dd6546623468f96',1,'VmaVulkanFunctions']]], - ['vkinvalidatemappedmemoryranges_399',['vkInvalidateMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a5c1093bc32386a8060c37c9f282078a1',1,'VmaVulkanFunctions']]], - ['vkmapmemory_400',['vkMapMemory',['../struct_vma_vulkan_functions.html#ab5c1f38dea3a2cf00dc9eb4f57218c49',1,'VmaVulkanFunctions']]], - ['vkunmapmemory_401',['vkUnmapMemory',['../struct_vma_vulkan_functions.html#acc798589736f0becb317fc2196c1d8b9',1,'VmaVulkanFunctions']]], - ['vulkanapiversion_402',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] + ['vkallocatememory_387',['vkAllocateMemory',['../struct_vma_vulkan_functions.html#a2943bf99dfd784a0e8f599d987e22e6c',1,'VmaVulkanFunctions']]], + ['vkbindbuffermemory_388',['vkBindBufferMemory',['../struct_vma_vulkan_functions.html#a94fc4f3a605d9880bb3c0ba2c2fc80b2',1,'VmaVulkanFunctions']]], + ['vkbindimagememory_389',['vkBindImageMemory',['../struct_vma_vulkan_functions.html#a1338d96a128a5ade648b8d934907c637',1,'VmaVulkanFunctions']]], + ['vkcmdcopybuffer_390',['vkCmdCopyBuffer',['../struct_vma_vulkan_functions.html#ae5c0db8c89a3b82593dc16aa6a49fa3a',1,'VmaVulkanFunctions']]], + ['vkcreatebuffer_391',['vkCreateBuffer',['../struct_vma_vulkan_functions.html#ae8084315a25006271a2edfc3a447519f',1,'VmaVulkanFunctions']]], + ['vkcreateimage_392',['vkCreateImage',['../struct_vma_vulkan_functions.html#a23ebe70be515b9b5010a1d691200e325',1,'VmaVulkanFunctions']]], + ['vkdestroybuffer_393',['vkDestroyBuffer',['../struct_vma_vulkan_functions.html#a7e054606faddb07f0e8556f3ed317d45',1,'VmaVulkanFunctions']]], + ['vkdestroyimage_394',['vkDestroyImage',['../struct_vma_vulkan_functions.html#a90b898227039b1dcb3520f6e91f09ffa',1,'VmaVulkanFunctions']]], + ['vkflushmappedmemoryranges_395',['vkFlushMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a33c322f4c4ad2810f8a9c97a277572f9',1,'VmaVulkanFunctions']]], + ['vkfreememory_396',['vkFreeMemory',['../struct_vma_vulkan_functions.html#a4c658701778564d62034255b5dda91b4',1,'VmaVulkanFunctions']]], + ['vkgetbuffermemoryrequirements_397',['vkGetBufferMemoryRequirements',['../struct_vma_vulkan_functions.html#a5b92901df89a4194b0d12f6071d4d143',1,'VmaVulkanFunctions']]], + ['vkgetimagememoryrequirements_398',['vkGetImageMemoryRequirements',['../struct_vma_vulkan_functions.html#a475f6f49f8debe4d10800592606d53f4',1,'VmaVulkanFunctions']]], + ['vkgetphysicaldevicememoryproperties_399',['vkGetPhysicalDeviceMemoryProperties',['../struct_vma_vulkan_functions.html#a60d25c33bba06bb8592e6875cbaa9830',1,'VmaVulkanFunctions']]], + ['vkgetphysicaldeviceproperties_400',['vkGetPhysicalDeviceProperties',['../struct_vma_vulkan_functions.html#a77b7a74082823e865dd6546623468f96',1,'VmaVulkanFunctions']]], + ['vkinvalidatemappedmemoryranges_401',['vkInvalidateMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a5c1093bc32386a8060c37c9f282078a1',1,'VmaVulkanFunctions']]], + ['vkmapmemory_402',['vkMapMemory',['../struct_vma_vulkan_functions.html#ab5c1f38dea3a2cf00dc9eb4f57218c49',1,'VmaVulkanFunctions']]], + ['vkunmapmemory_403',['vkUnmapMemory',['../struct_vma_vulkan_functions.html#acc798589736f0becb317fc2196c1d8b9',1,'VmaVulkanFunctions']]], + ['vulkanapiversion_404',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] ]; diff --git a/docs/html/vk__mem__alloc_8h.html b/docs/html/vk__mem__alloc_8h.html index f568ef9..667d4ea 100644 --- a/docs/html/vk__mem__alloc_8h.html +++ b/docs/html/vk__mem__alloc_8h.html @@ -451,6 +451,9 @@ Functions   VkResult vmaCreateBuffer (VmaAllocator allocator, const VkBufferCreateInfo *pBufferCreateInfo, const VmaAllocationCreateInfo *pAllocationCreateInfo, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)   +VkResult vmaCreateBufferWithAlignment (VmaAllocator allocator, const VkBufferCreateInfo *pBufferCreateInfo, const VmaAllocationCreateInfo *pAllocationCreateInfo, VkDeviceSize minAlignment, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo) + Creates a buffer with additional minimum alignment. More...
    +  void vmaDestroyBuffer (VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)  Destroys Vulkan buffer and frees allocated memory. More...
      @@ -2010,6 +2013,67 @@ Functions

    If VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, VK_KHR_dedicated_allocation extension is used internally to query driver whether it requires or prefers the new buffer to have dedicated allocation. If yes, and if dedicated allocation is possible (VmaAllocationCreateInfo::pool is null and VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated allocation for this buffer, just like when using VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT.

    Note
    This function creates a new VkBuffer. Sub-allocation of parts of one large buffer, although recommended as a good practice, is out of scope of this library and could be implemented by the user as a higher-level logic on top of VMA.
    + + + +

    ◆ vmaCreateBufferWithAlignment()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VkResult vmaCreateBufferWithAlignment (VmaAllocator allocator,
    const VkBufferCreateInfo * pBufferCreateInfo,
    const VmaAllocationCreateInfopAllocationCreateInfo,
    VkDeviceSize minAlignment,
    VkBuffer * pBuffer,
    VmaAllocationpAllocation,
    VmaAllocationInfopAllocationInfo 
    )
    +
    + +

    Creates a buffer with additional minimum alignment.

    +

    Similar to vmaCreateBuffer() but provides additional parameter minAlignment which allows to specify custom, minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. for interop with OpenGL.

    +
    diff --git a/docs/html/vk__mem__alloc_8h_source.html b/docs/html/vk__mem__alloc_8h_source.html index 3444b00..3578c9e 100644 --- a/docs/html/vk__mem__alloc_8h_source.html +++ b/docs/html/vk__mem__alloc_8h_source.html @@ -814,15612 +814,15723 @@ $(function() {
    3987  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
    3988  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
    3989 
    -
    4001 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
    -
    4002  VmaAllocator VMA_NOT_NULL allocator,
    -
    4003  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer,
    -
    4004  VmaAllocation VMA_NULLABLE allocation);
    -
    4005 
    -
    4007 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
    -
    4008  VmaAllocator VMA_NOT_NULL allocator,
    -
    4009  const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo,
    -
    4010  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
    -
    4011  VkImage VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pImage,
    -
    4012  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
    -
    4013  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
    -
    4014 
    -
    4026 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
    -
    4027  VmaAllocator VMA_NOT_NULL allocator,
    -
    4028  VkImage VMA_NULLABLE_NON_DISPATCHABLE image,
    -
    4029  VmaAllocation VMA_NULLABLE allocation);
    -
    4030 
    -
    4031 #ifdef __cplusplus
    -
    4032 }
    -
    4033 #endif
    -
    4034 
    -
    4035 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
    -
    4036 
    -
    4037 // For Visual Studio IntelliSense.
    -
    4038 #if defined(__cplusplus) && defined(__INTELLISENSE__)
    -
    4039 #define VMA_IMPLEMENTATION
    -
    4040 #endif
    -
    4041 
    -
    4042 #ifdef VMA_IMPLEMENTATION
    -
    4043 #undef VMA_IMPLEMENTATION
    -
    4044 
    -
    4045 #include <cstdint>
    -
    4046 #include <cstdlib>
    -
    4047 #include <cstring>
    -
    4048 #include <utility>
    +
    3996 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment(
    +
    3997  VmaAllocator VMA_NOT_NULL allocator,
    +
    3998  const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo,
    +
    3999  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
    +
    4000  VkDeviceSize minAlignment,
    +
    4001  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pBuffer,
    +
    4002  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
    +
    4003  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
    +
    4004 
    +
    4016 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
    +
    4017  VmaAllocator VMA_NOT_NULL allocator,
    +
    4018  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer,
    +
    4019  VmaAllocation VMA_NULLABLE allocation);
    +
    4020 
    +
    4022 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
    +
    4023  VmaAllocator VMA_NOT_NULL allocator,
    +
    4024  const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo,
    +
    4025  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
    +
    4026  VkImage VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pImage,
    +
    4027  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
    +
    4028  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
    +
    4029 
    +
    4041 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
    +
    4042  VmaAllocator VMA_NOT_NULL allocator,
    +
    4043  VkImage VMA_NULLABLE_NON_DISPATCHABLE image,
    +
    4044  VmaAllocation VMA_NULLABLE allocation);
    +
    4045 
    +
    4046 #ifdef __cplusplus
    +
    4047 }
    +
    4048 #endif
    4049 
    -
    4050 #if VMA_RECORDING_ENABLED
    -
    4051  #include <chrono>
    -
    4052  #if defined(_WIN32)
    -
    4053  #include <windows.h>
    -
    4054  #else
    -
    4055  #include <sstream>
    -
    4056  #include <thread>
    -
    4057  #endif
    -
    4058 #endif
    +
    4050 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
    +
    4051 
    +
    4052 // For Visual Studio IntelliSense.
    +
    4053 #if defined(__cplusplus) && defined(__INTELLISENSE__)
    +
    4054 #define VMA_IMPLEMENTATION
    +
    4055 #endif
    +
    4056 
    +
    4057 #ifdef VMA_IMPLEMENTATION
    +
    4058 #undef VMA_IMPLEMENTATION
    4059 
    -
    4060 /*******************************************************************************
    -
    4061 CONFIGURATION SECTION
    -
    4062 
    -
    4063 Define some of these macros before each #include of this header or change them
    -
    4064 here if you need other then default behavior depending on your environment.
    -
    4065 */
    -
    4066 
    -
    4067 /*
    -
    4068 Define this macro to 1 to make the library fetch pointers to Vulkan functions
    -
    4069 internally, like:
    -
    4070 
    -
    4071  vulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
    -
    4072 */
    -
    4073 #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES)
    -
    4074  #define VMA_STATIC_VULKAN_FUNCTIONS 1
    -
    4075 #endif
    -
    4076 
    -
    4077 /*
    -
    4078 Define this macro to 1 to make the library fetch pointers to Vulkan functions
    -
    4079 internally, like:
    -
    4080 
    -
    4081  vulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkGetDeviceProcAddr(m_hDevice, vkAllocateMemory);
    -
    4082 */
    -
    4083 #if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS)
    -
    4084  #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
    -
    4085  #if defined(VK_NO_PROTOTYPES)
    -
    4086  extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
    -
    4087  extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
    -
    4088  #endif
    -
    4089 #endif
    -
    4090 
    -
    4091 // Define this macro to 1 to make the library use STL containers instead of its own implementation.
    -
    4092 //#define VMA_USE_STL_CONTAINERS 1
    -
    4093 
    -
    4094 /* Set this macro to 1 to make the library including and using STL containers:
    -
    4095 std::pair, std::vector, std::list, std::unordered_map.
    -
    4096 
    -
    4097 Set it to 0 or undefined to make the library using its own implementation of
    -
    4098 the containers.
    -
    4099 */
    -
    4100 #if VMA_USE_STL_CONTAINERS
    -
    4101  #define VMA_USE_STL_VECTOR 1
    -
    4102  #define VMA_USE_STL_UNORDERED_MAP 1
    -
    4103  #define VMA_USE_STL_LIST 1
    +
    4060 #include <cstdint>
    +
    4061 #include <cstdlib>
    +
    4062 #include <cstring>
    +
    4063 #include <utility>
    +
    4064 
    +
    4065 #if VMA_RECORDING_ENABLED
    +
    4066  #include <chrono>
    +
    4067  #if defined(_WIN32)
    +
    4068  #include <windows.h>
    +
    4069  #else
    +
    4070  #include <sstream>
    +
    4071  #include <thread>
    +
    4072  #endif
    +
    4073 #endif
    +
    4074 
    +
    4075 /*******************************************************************************
    +
    4076 CONFIGURATION SECTION
    +
    4077 
    +
    4078 Define some of these macros before each #include of this header or change them
    +
    4079 here if you need other then default behavior depending on your environment.
    +
    4080 */
    +
    4081 
    +
    4082 /*
    +
    4083 Define this macro to 1 to make the library fetch pointers to Vulkan functions
    +
    4084 internally, like:
    +
    4085 
    +
    4086  vulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
    +
    4087 */
    +
    4088 #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES)
    +
    4089  #define VMA_STATIC_VULKAN_FUNCTIONS 1
    +
    4090 #endif
    +
    4091 
    +
    4092 /*
    +
    4093 Define this macro to 1 to make the library fetch pointers to Vulkan functions
    +
    4094 internally, like:
    +
    4095 
    +
    4096  vulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkGetDeviceProcAddr(m_hDevice, vkAllocateMemory);
    +
    4097 */
    +
    4098 #if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS)
    +
    4099  #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
    +
    4100  #if defined(VK_NO_PROTOTYPES)
    +
    4101  extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
    +
    4102  extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
    +
    4103  #endif
    4104 #endif
    4105 
    -
    4106 #ifndef VMA_USE_STL_SHARED_MUTEX
    -
    4107  // Compiler conforms to C++17.
    -
    4108  #if __cplusplus >= 201703L
    -
    4109  #define VMA_USE_STL_SHARED_MUTEX 1
    -
    4110  // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus
    -
    4111  // Otherwise it's always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2.
    -
    4112  // See: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
    -
    4113  #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L
    -
    4114  #define VMA_USE_STL_SHARED_MUTEX 1
    -
    4115  #else
    -
    4116  #define VMA_USE_STL_SHARED_MUTEX 0
    -
    4117  #endif
    -
    4118 #endif
    -
    4119 
    -
    4120 /*
    -
    4121 THESE INCLUDES ARE NOT ENABLED BY DEFAULT.
    -
    4122 Library has its own container implementation.
    -
    4123 */
    -
    4124 #if VMA_USE_STL_VECTOR
    -
    4125  #include <vector>
    -
    4126 #endif
    -
    4127 
    -
    4128 #if VMA_USE_STL_UNORDERED_MAP
    -
    4129  #include <unordered_map>
    -
    4130 #endif
    -
    4131 
    -
    4132 #if VMA_USE_STL_LIST
    -
    4133  #include <list>
    -
    4134 #endif
    -
    4135 
    -
    4136 /*
    -
    4137 Following headers are used in this CONFIGURATION section only, so feel free to
    -
    4138 remove them if not needed.
    -
    4139 */
    -
    4140 #include <cassert> // for assert
    -
    4141 #include <algorithm> // for min, max
    -
    4142 #include <mutex>
    -
    4143 
    -
    4144 #ifndef VMA_NULL
    -
    4145  // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
    -
    4146  #define VMA_NULL nullptr
    -
    4147 #endif
    -
    4148 
    -
    4149 #if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
    -
    4150 #include <cstdlib>
    -
    4151 static void* vma_aligned_alloc(size_t alignment, size_t size)
    -
    4152 {
    -
    4153  // alignment must be >= sizeof(void*)
    -
    4154  if(alignment < sizeof(void*))
    -
    4155  {
    -
    4156  alignment = sizeof(void*);
    -
    4157  }
    +
    4106 // Define this macro to 1 to make the library use STL containers instead of its own implementation.
    +
    4107 //#define VMA_USE_STL_CONTAINERS 1
    +
    4108 
    +
    4109 /* Set this macro to 1 to make the library including and using STL containers:
    +
    4110 std::pair, std::vector, std::list, std::unordered_map.
    +
    4111 
    +
    4112 Set it to 0 or undefined to make the library using its own implementation of
    +
    4113 the containers.
    +
    4114 */
    +
    4115 #if VMA_USE_STL_CONTAINERS
    +
    4116  #define VMA_USE_STL_VECTOR 1
    +
    4117  #define VMA_USE_STL_UNORDERED_MAP 1
    +
    4118  #define VMA_USE_STL_LIST 1
    +
    4119 #endif
    +
    4120 
    +
    4121 #ifndef VMA_USE_STL_SHARED_MUTEX
    +
    4122  // Compiler conforms to C++17.
    +
    4123  #if __cplusplus >= 201703L
    +
    4124  #define VMA_USE_STL_SHARED_MUTEX 1
    +
    4125  // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus
    +
    4126  // Otherwise it's always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2.
    +
    4127  // See: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
    +
    4128  #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L
    +
    4129  #define VMA_USE_STL_SHARED_MUTEX 1
    +
    4130  #else
    +
    4131  #define VMA_USE_STL_SHARED_MUTEX 0
    +
    4132  #endif
    +
    4133 #endif
    +
    4134 
    +
    4135 /*
    +
    4136 THESE INCLUDES ARE NOT ENABLED BY DEFAULT.
    +
    4137 Library has its own container implementation.
    +
    4138 */
    +
    4139 #if VMA_USE_STL_VECTOR
    +
    4140  #include <vector>
    +
    4141 #endif
    +
    4142 
    +
    4143 #if VMA_USE_STL_UNORDERED_MAP
    +
    4144  #include <unordered_map>
    +
    4145 #endif
    +
    4146 
    +
    4147 #if VMA_USE_STL_LIST
    +
    4148  #include <list>
    +
    4149 #endif
    +
    4150 
    +
    4151 /*
    +
    4152 Following headers are used in this CONFIGURATION section only, so feel free to
    +
    4153 remove them if not needed.
    +
    4154 */
    +
    4155 #include <cassert> // for assert
    +
    4156 #include <algorithm> // for min, max
    +
    4157 #include <mutex>
    4158 
    -
    4159  return memalign(alignment, size);
    -
    4160 }
    -
    4161 #elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC))
    -
    4162 #include <cstdlib>
    +
    4159 #ifndef VMA_NULL
    +
    4160  // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
    +
    4161  #define VMA_NULL nullptr
    +
    4162 #endif
    4163 
    -
    4164 #if defined(__APPLE__)
    -
    4165 #include <AvailabilityMacros.h>
    -
    4166 #endif
    -
    4167 
    -
    4168 static void* vma_aligned_alloc(size_t alignment, size_t size)
    -
    4169 {
    -
    4170 #if defined(__APPLE__) && (defined(MAC_OS_X_VERSION_10_16) || defined(__IPHONE_14_0))
    -
    4171 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
    -
    4172  // For C++14, usr/include/malloc/_malloc.h declares aligned_alloc()) only
    -
    4173  // with the MacOSX11.0 SDK in Xcode 12 (which is what adds
    -
    4174  // MAC_OS_X_VERSION_10_16), even though the function is marked
    -
    4175  // availabe for 10.15. That's why the preprocessor checks for 10.16 but
    -
    4176  // the __builtin_available checks for 10.15.
    -
    4177  // People who use C++17 could call aligned_alloc with the 10.15 SDK already.
    -
    4178  if (__builtin_available(macOS 10.15, iOS 13, *))
    -
    4179  return aligned_alloc(alignment, size);
    -
    4180 #endif
    +
    4164 #if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
    +
    4165 #include <cstdlib>
    +
    4166 static void* vma_aligned_alloc(size_t alignment, size_t size)
    +
    4167 {
    +
    4168  // alignment must be >= sizeof(void*)
    +
    4169  if(alignment < sizeof(void*))
    +
    4170  {
    +
    4171  alignment = sizeof(void*);
    +
    4172  }
    +
    4173 
    +
    4174  return memalign(alignment, size);
    +
    4175 }
    +
    4176 #elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC))
    +
    4177 #include <cstdlib>
    +
    4178 
    +
    4179 #if defined(__APPLE__)
    +
    4180 #include <AvailabilityMacros.h>
    4181 #endif
    -
    4182  // alignment must be >= sizeof(void*)
    -
    4183  if(alignment < sizeof(void*))
    -
    4184  {
    -
    4185  alignment = sizeof(void*);
    -
    4186  }
    -
    4187 
    -
    4188  void *pointer;
    -
    4189  if(posix_memalign(&pointer, alignment, size) == 0)
    -
    4190  return pointer;
    -
    4191  return VMA_NULL;
    -
    4192 }
    -
    4193 #elif defined(_WIN32)
    -
    4194 static void* vma_aligned_alloc(size_t alignment, size_t size)
    -
    4195 {
    -
    4196  return _aligned_malloc(size, alignment);
    -
    4197 }
    -
    4198 #else
    -
    4199 static void* vma_aligned_alloc(size_t alignment, size_t size)
    -
    4200 {
    -
    4201  return aligned_alloc(alignment, size);
    -
    4202 }
    -
    4203 #endif
    -
    4204 
    -
    4205 #if defined(_WIN32)
    -
    4206 static void vma_aligned_free(void* ptr)
    -
    4207 {
    -
    4208  _aligned_free(ptr);
    -
    4209 }
    -
    4210 #else
    -
    4211 static void vma_aligned_free(void* VMA_NULLABLE ptr)
    -
    4212 {
    -
    4213  free(ptr);
    -
    4214 }
    -
    4215 #endif
    -
    4216 
    -
    4217 // If your compiler is not compatible with C++11 and definition of
    -
    4218 // aligned_alloc() function is missing, uncommeting following line may help:
    +
    4182 
    +
    4183 static void* vma_aligned_alloc(size_t alignment, size_t size)
    +
    4184 {
    +
    4185 #if defined(__APPLE__) && (defined(MAC_OS_X_VERSION_10_16) || defined(__IPHONE_14_0))
    +
    4186 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
    +
    4187  // For C++14, usr/include/malloc/_malloc.h declares aligned_alloc()) only
    +
    4188  // with the MacOSX11.0 SDK in Xcode 12 (which is what adds
    +
    4189  // MAC_OS_X_VERSION_10_16), even though the function is marked
    +
    4190  // availabe for 10.15. That's why the preprocessor checks for 10.16 but
    +
    4191  // the __builtin_available checks for 10.15.
    +
    4192  // People who use C++17 could call aligned_alloc with the 10.15 SDK already.
    +
    4193  if (__builtin_available(macOS 10.15, iOS 13, *))
    +
    4194  return aligned_alloc(alignment, size);
    +
    4195 #endif
    +
    4196 #endif
    +
    4197  // alignment must be >= sizeof(void*)
    +
    4198  if(alignment < sizeof(void*))
    +
    4199  {
    +
    4200  alignment = sizeof(void*);
    +
    4201  }
    +
    4202 
    +
    4203  void *pointer;
    +
    4204  if(posix_memalign(&pointer, alignment, size) == 0)
    +
    4205  return pointer;
    +
    4206  return VMA_NULL;
    +
    4207 }
    +
    4208 #elif defined(_WIN32)
    +
    4209 static void* vma_aligned_alloc(size_t alignment, size_t size)
    +
    4210 {
    +
    4211  return _aligned_malloc(size, alignment);
    +
    4212 }
    +
    4213 #else
    +
    4214 static void* vma_aligned_alloc(size_t alignment, size_t size)
    +
    4215 {
    +
    4216  return aligned_alloc(alignment, size);
    +
    4217 }
    +
    4218 #endif
    4219 
    -
    4220 //#include <malloc.h>
    -
    4221 
    -
    4222 // Normal assert to check for programmer's errors, especially in Debug configuration.
    -
    4223 #ifndef VMA_ASSERT
    -
    4224  #ifdef NDEBUG
    -
    4225  #define VMA_ASSERT(expr)
    -
    4226  #else
    -
    4227  #define VMA_ASSERT(expr) assert(expr)
    -
    4228  #endif
    -
    4229 #endif
    -
    4230 
    -
    4231 // Assert that will be called very often, like inside data structures e.g. operator[].
    -
    4232 // Making it non-empty can make program slow.
    -
    4233 #ifndef VMA_HEAVY_ASSERT
    -
    4234  #ifdef NDEBUG
    -
    4235  #define VMA_HEAVY_ASSERT(expr)
    -
    4236  #else
    -
    4237  #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
    -
    4238  #endif
    -
    4239 #endif
    -
    4240 
    -
    4241 #ifndef VMA_ALIGN_OF
    -
    4242  #define VMA_ALIGN_OF(type) (__alignof(type))
    -
    4243 #endif
    -
    4244 
    -
    4245 #ifndef VMA_SYSTEM_ALIGNED_MALLOC
    -
    4246  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size))
    -
    4247 #endif
    -
    4248 
    -
    4249 #ifndef VMA_SYSTEM_ALIGNED_FREE
    -
    4250  // VMA_SYSTEM_FREE is the old name, but might have been defined by the user
    -
    4251  #if defined(VMA_SYSTEM_FREE)
    -
    4252  #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr)
    -
    4253  #else
    -
    4254  #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr)
    -
    4255  #endif
    -
    4256 #endif
    -
    4257 
    -
    4258 #ifndef VMA_MIN
    -
    4259  #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
    -
    4260 #endif
    -
    4261 
    -
    4262 #ifndef VMA_MAX
    -
    4263  #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
    -
    4264 #endif
    -
    4265 
    -
    4266 #ifndef VMA_SWAP
    -
    4267  #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
    -
    4268 #endif
    -
    4269 
    -
    4270 #ifndef VMA_SORT
    -
    4271  #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
    -
    4272 #endif
    -
    4273 
    -
    4274 #ifndef VMA_DEBUG_LOG
    -
    4275  #define VMA_DEBUG_LOG(format, ...)
    -
    4276  /*
    -
    4277  #define VMA_DEBUG_LOG(format, ...) do { \
    -
    4278  printf(format, __VA_ARGS__); \
    -
    4279  printf("\n"); \
    -
    4280  } while(false)
    -
    4281  */
    -
    4282 #endif
    -
    4283 
    -
    4284 // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
    -
    4285 #if VMA_STATS_STRING_ENABLED
    -
    4286  static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num)
    -
    4287  {
    -
    4288  snprintf(outStr, strLen, "%u", static_cast<unsigned int>(num));
    -
    4289  }
    -
    4290  static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num)
    -
    4291  {
    -
    4292  snprintf(outStr, strLen, "%llu", static_cast<unsigned long long>(num));
    -
    4293  }
    -
    4294  static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr)
    -
    4295  {
    -
    4296  snprintf(outStr, strLen, "%p", ptr);
    -
    4297  }
    -
    4298 #endif
    -
    4299 
    -
    4300 #ifndef VMA_MUTEX
    -
    4301  class VmaMutex
    +
    4220 #if defined(_WIN32)
    +
    4221 static void vma_aligned_free(void* ptr)
    +
    4222 {
    +
    4223  _aligned_free(ptr);
    +
    4224 }
    +
    4225 #else
    +
    4226 static void vma_aligned_free(void* VMA_NULLABLE ptr)
    +
    4227 {
    +
    4228  free(ptr);
    +
    4229 }
    +
    4230 #endif
    +
    4231 
    +
    4232 // If your compiler is not compatible with C++11 and definition of
    +
    4233 // aligned_alloc() function is missing, uncommeting following line may help:
    +
    4234 
    +
    4235 //#include <malloc.h>
    +
    4236 
    +
    4237 // Normal assert to check for programmer's errors, especially in Debug configuration.
    +
    4238 #ifndef VMA_ASSERT
    +
    4239  #ifdef NDEBUG
    +
    4240  #define VMA_ASSERT(expr)
    +
    4241  #else
    +
    4242  #define VMA_ASSERT(expr) assert(expr)
    +
    4243  #endif
    +
    4244 #endif
    +
    4245 
    +
    4246 // Assert that will be called very often, like inside data structures e.g. operator[].
    +
    4247 // Making it non-empty can make program slow.
    +
    4248 #ifndef VMA_HEAVY_ASSERT
    +
    4249  #ifdef NDEBUG
    +
    4250  #define VMA_HEAVY_ASSERT(expr)
    +
    4251  #else
    +
    4252  #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
    +
    4253  #endif
    +
    4254 #endif
    +
    4255 
    +
    4256 #ifndef VMA_ALIGN_OF
    +
    4257  #define VMA_ALIGN_OF(type) (__alignof(type))
    +
    4258 #endif
    +
    4259 
    +
    4260 #ifndef VMA_SYSTEM_ALIGNED_MALLOC
    +
    4261  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size))
    +
    4262 #endif
    +
    4263 
    +
    4264 #ifndef VMA_SYSTEM_ALIGNED_FREE
    +
    4265  // VMA_SYSTEM_FREE is the old name, but might have been defined by the user
    +
    4266  #if defined(VMA_SYSTEM_FREE)
    +
    4267  #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr)
    +
    4268  #else
    +
    4269  #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr)
    +
    4270  #endif
    +
    4271 #endif
    +
    4272 
    +
    4273 #ifndef VMA_MIN
    +
    4274  #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
    +
    4275 #endif
    +
    4276 
    +
    4277 #ifndef VMA_MAX
    +
    4278  #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
    +
    4279 #endif
    +
    4280 
    +
    4281 #ifndef VMA_SWAP
    +
    4282  #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
    +
    4283 #endif
    +
    4284 
    +
    4285 #ifndef VMA_SORT
    +
    4286  #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
    +
    4287 #endif
    +
    4288 
    +
    4289 #ifndef VMA_DEBUG_LOG
    +
    4290  #define VMA_DEBUG_LOG(format, ...)
    +
    4291  /*
    +
    4292  #define VMA_DEBUG_LOG(format, ...) do { \
    +
    4293  printf(format, __VA_ARGS__); \
    +
    4294  printf("\n"); \
    +
    4295  } while(false)
    +
    4296  */
    +
    4297 #endif
    +
    4298 
    +
    4299 // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
    +
    4300 #if VMA_STATS_STRING_ENABLED
    +
    4301  static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num)
    4302  {
    -
    4303  public:
    -
    4304  void Lock() { m_Mutex.lock(); }
    -
    4305  void Unlock() { m_Mutex.unlock(); }
    -
    4306  bool TryLock() { return m_Mutex.try_lock(); }
    -
    4307  private:
    -
    4308  std::mutex m_Mutex;
    -
    4309  };
    -
    4310  #define VMA_MUTEX VmaMutex
    -
    4311 #endif
    -
    4312 
    -
    4313 // Read-write mutex, where "read" is shared access, "write" is exclusive access.
    -
    4314 #ifndef VMA_RW_MUTEX
    -
    4315  #if VMA_USE_STL_SHARED_MUTEX
    -
    4316  // Use std::shared_mutex from C++17.
    -
    4317  #include <shared_mutex>
    -
    4318  class VmaRWMutex
    -
    4319  {
    -
    4320  public:
    -
    4321  void LockRead() { m_Mutex.lock_shared(); }
    -
    4322  void UnlockRead() { m_Mutex.unlock_shared(); }
    -
    4323  bool TryLockRead() { return m_Mutex.try_lock_shared(); }
    -
    4324  void LockWrite() { m_Mutex.lock(); }
    -
    4325  void UnlockWrite() { m_Mutex.unlock(); }
    -
    4326  bool TryLockWrite() { return m_Mutex.try_lock(); }
    -
    4327  private:
    -
    4328  std::shared_mutex m_Mutex;
    -
    4329  };
    -
    4330  #define VMA_RW_MUTEX VmaRWMutex
    -
    4331  #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600
    -
    4332  // Use SRWLOCK from WinAPI.
    -
    4333  // Minimum supported client = Windows Vista, server = Windows Server 2008.
    -
    4334  class VmaRWMutex
    -
    4335  {
    -
    4336  public:
    -
    4337  VmaRWMutex() { InitializeSRWLock(&m_Lock); }
    -
    4338  void LockRead() { AcquireSRWLockShared(&m_Lock); }
    -
    4339  void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
    -
    4340  bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; }
    -
    4341  void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
    -
    4342  void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
    -
    4343  bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; }
    -
    4344  private:
    -
    4345  SRWLOCK m_Lock;
    -
    4346  };
    -
    4347  #define VMA_RW_MUTEX VmaRWMutex
    -
    4348  #else
    -
    4349  // Less efficient fallback: Use normal mutex.
    -
    4350  class VmaRWMutex
    -
    4351  {
    -
    4352  public:
    -
    4353  void LockRead() { m_Mutex.Lock(); }
    -
    4354  void UnlockRead() { m_Mutex.Unlock(); }
    -
    4355  bool TryLockRead() { return m_Mutex.TryLock(); }
    -
    4356  void LockWrite() { m_Mutex.Lock(); }
    -
    4357  void UnlockWrite() { m_Mutex.Unlock(); }
    -
    4358  bool TryLockWrite() { return m_Mutex.TryLock(); }
    +
    4303  snprintf(outStr, strLen, "%u", static_cast<unsigned int>(num));
    +
    4304  }
    +
    4305  static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num)
    +
    4306  {
    +
    4307  snprintf(outStr, strLen, "%llu", static_cast<unsigned long long>(num));
    +
    4308  }
    +
    4309  static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr)
    +
    4310  {
    +
    4311  snprintf(outStr, strLen, "%p", ptr);
    +
    4312  }
    +
    4313 #endif
    +
    4314 
    +
    4315 #ifndef VMA_MUTEX
    +
    4316  class VmaMutex
    +
    4317  {
    +
    4318  public:
    +
    4319  void Lock() { m_Mutex.lock(); }
    +
    4320  void Unlock() { m_Mutex.unlock(); }
    +
    4321  bool TryLock() { return m_Mutex.try_lock(); }
    +
    4322  private:
    +
    4323  std::mutex m_Mutex;
    +
    4324  };
    +
    4325  #define VMA_MUTEX VmaMutex
    +
    4326 #endif
    +
    4327 
    +
    4328 // Read-write mutex, where "read" is shared access, "write" is exclusive access.
    +
    4329 #ifndef VMA_RW_MUTEX
    +
    4330  #if VMA_USE_STL_SHARED_MUTEX
    +
    4331  // Use std::shared_mutex from C++17.
    +
    4332  #include <shared_mutex>
    +
    4333  class VmaRWMutex
    +
    4334  {
    +
    4335  public:
    +
    4336  void LockRead() { m_Mutex.lock_shared(); }
    +
    4337  void UnlockRead() { m_Mutex.unlock_shared(); }
    +
    4338  bool TryLockRead() { return m_Mutex.try_lock_shared(); }
    +
    4339  void LockWrite() { m_Mutex.lock(); }
    +
    4340  void UnlockWrite() { m_Mutex.unlock(); }
    +
    4341  bool TryLockWrite() { return m_Mutex.try_lock(); }
    +
    4342  private:
    +
    4343  std::shared_mutex m_Mutex;
    +
    4344  };
    +
    4345  #define VMA_RW_MUTEX VmaRWMutex
    +
    4346  #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600
    +
    4347  // Use SRWLOCK from WinAPI.
    +
    4348  // Minimum supported client = Windows Vista, server = Windows Server 2008.
    +
    4349  class VmaRWMutex
    +
    4350  {
    +
    4351  public:
    +
    4352  VmaRWMutex() { InitializeSRWLock(&m_Lock); }
    +
    4353  void LockRead() { AcquireSRWLockShared(&m_Lock); }
    +
    4354  void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
    +
    4355  bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; }
    +
    4356  void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
    +
    4357  void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
    +
    4358  bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; }
    4359  private:
    -
    4360  VMA_MUTEX m_Mutex;
    +
    4360  SRWLOCK m_Lock;
    4361  };
    4362  #define VMA_RW_MUTEX VmaRWMutex
    -
    4363  #endif // #if VMA_USE_STL_SHARED_MUTEX
    -
    4364 #endif // #ifndef VMA_RW_MUTEX
    -
    4365 
    -
    4366 /*
    -
    4367 If providing your own implementation, you need to implement a subset of std::atomic.
    -
    4368 */
    -
    4369 #ifndef VMA_ATOMIC_UINT32
    -
    4370  #include <atomic>
    -
    4371  #define VMA_ATOMIC_UINT32 std::atomic<uint32_t>
    -
    4372 #endif
    -
    4373 
    -
    4374 #ifndef VMA_ATOMIC_UINT64
    -
    4375  #include <atomic>
    -
    4376  #define VMA_ATOMIC_UINT64 std::atomic<uint64_t>
    -
    4377 #endif
    -
    4378 
    -
    4379 #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY
    -
    4384  #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0)
    -
    4385 #endif
    -
    4386 
    -
    4387 #ifndef VMA_MIN_ALIGNMENT
    -
    4392  #ifdef VMA_DEBUG_ALIGNMENT // Old name
    -
    4393  #define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT
    -
    4394  #else
    -
    4395  #define VMA_MIN_ALIGNMENT (1)
    -
    4396  #endif
    -
    4397 #endif
    -
    4398 
    -
    4399 #ifndef VMA_DEBUG_MARGIN
    -
    4404  #define VMA_DEBUG_MARGIN (0)
    -
    4405 #endif
    -
    4406 
    -
    4407 #ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS
    -
    4412  #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0)
    -
    4413 #endif
    -
    4414 
    -
    4415 #ifndef VMA_DEBUG_DETECT_CORRUPTION
    -
    4421  #define VMA_DEBUG_DETECT_CORRUPTION (0)
    -
    4422 #endif
    -
    4423 
    -
    4424 #ifndef VMA_DEBUG_GLOBAL_MUTEX
    -
    4429  #define VMA_DEBUG_GLOBAL_MUTEX (0)
    -
    4430 #endif
    -
    4431 
    -
    4432 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
    -
    4437  #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
    -
    4438 #endif
    -
    4439 
    -
    4440 #ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
    -
    4441  /*
    -
    4442  Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount
    -
    4443  and return error instead of leaving up to Vulkan implementation what to do in such cases.
    -
    4444  */
    -
    4445  #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0)
    -
    4446 #endif
    -
    4447 
    -
    4448 #ifndef VMA_SMALL_HEAP_MAX_SIZE
    -
    4450  #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024)
    -
    4451 #endif
    -
    4452 
    -
    4453 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
    -
    4455  #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024)
    -
    4456 #endif
    -
    4457 
    -
    4458 #ifndef VMA_CLASS_NO_COPY
    -
    4459  #define VMA_CLASS_NO_COPY(className) \
    -
    4460  private: \
    -
    4461  className(const className&) = delete; \
    -
    4462  className& operator=(const className&) = delete;
    -
    4463 #endif
    -
    4464 
    -
    4465 static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
    -
    4466 
    -
    4467 // Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F.
    -
    4468 static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666;
    -
    4469 
    -
    4470 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC;
    -
    4471 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF;
    +
    4363  #else
    +
    4364  // Less efficient fallback: Use normal mutex.
    +
    4365  class VmaRWMutex
    +
    4366  {
    +
    4367  public:
    +
    4368  void LockRead() { m_Mutex.Lock(); }
    +
    4369  void UnlockRead() { m_Mutex.Unlock(); }
    +
    4370  bool TryLockRead() { return m_Mutex.TryLock(); }
    +
    4371  void LockWrite() { m_Mutex.Lock(); }
    +
    4372  void UnlockWrite() { m_Mutex.Unlock(); }
    +
    4373  bool TryLockWrite() { return m_Mutex.TryLock(); }
    +
    4374  private:
    +
    4375  VMA_MUTEX m_Mutex;
    +
    4376  };
    +
    4377  #define VMA_RW_MUTEX VmaRWMutex
    +
    4378  #endif // #if VMA_USE_STL_SHARED_MUTEX
    +
    4379 #endif // #ifndef VMA_RW_MUTEX
    +
    4380 
    +
    4381 /*
    +
    4382 If providing your own implementation, you need to implement a subset of std::atomic.
    +
    4383 */
    +
    4384 #ifndef VMA_ATOMIC_UINT32
    +
    4385  #include <atomic>
    +
    4386  #define VMA_ATOMIC_UINT32 std::atomic<uint32_t>
    +
    4387 #endif
    +
    4388 
    +
    4389 #ifndef VMA_ATOMIC_UINT64
    +
    4390  #include <atomic>
    +
    4391  #define VMA_ATOMIC_UINT64 std::atomic<uint64_t>
    +
    4392 #endif
    +
    4393 
    +
    4394 #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY
    +
    4399  #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0)
    +
    4400 #endif
    +
    4401 
    +
    4402 #ifndef VMA_MIN_ALIGNMENT
    +
    4407  #ifdef VMA_DEBUG_ALIGNMENT // Old name
    +
    4408  #define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT
    +
    4409  #else
    +
    4410  #define VMA_MIN_ALIGNMENT (1)
    +
    4411  #endif
    +
    4412 #endif
    +
    4413 
    +
    4414 #ifndef VMA_DEBUG_MARGIN
    +
    4419  #define VMA_DEBUG_MARGIN (0)
    +
    4420 #endif
    +
    4421 
    +
    4422 #ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS
    +
    4427  #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0)
    +
    4428 #endif
    +
    4429 
    +
    4430 #ifndef VMA_DEBUG_DETECT_CORRUPTION
    +
    4436  #define VMA_DEBUG_DETECT_CORRUPTION (0)
    +
    4437 #endif
    +
    4438 
    +
    4439 #ifndef VMA_DEBUG_GLOBAL_MUTEX
    +
    4444  #define VMA_DEBUG_GLOBAL_MUTEX (0)
    +
    4445 #endif
    +
    4446 
    +
    4447 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
    +
    4452  #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
    +
    4453 #endif
    +
    4454 
    +
    4455 #ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
    +
    4456  /*
    +
    4457  Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount
    +
    4458  and return error instead of leaving up to Vulkan implementation what to do in such cases.
    +
    4459  */
    +
    4460  #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0)
    +
    4461 #endif
    +
    4462 
    +
    4463 #ifndef VMA_SMALL_HEAP_MAX_SIZE
    +
    4465  #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024)
    +
    4466 #endif
    +
    4467 
    +
    4468 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
    +
    4470  #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024)
    +
    4471 #endif
    4472 
    -
    4473 /*******************************************************************************
    -
    4474 END OF CONFIGURATION
    -
    4475 */
    -
    4476 
    -
    4477 // # Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants.
    -
    4478 
    -
    4479 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040;
    -
    4480 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080;
    -
    4481 static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000;
    -
    4482 
    -
    4483 static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
    +
    4473 #ifndef VMA_CLASS_NO_COPY
    +
    4474  #define VMA_CLASS_NO_COPY(className) \
    +
    4475  private: \
    +
    4476  className(const className&) = delete; \
    +
    4477  className& operator=(const className&) = delete;
    +
    4478 #endif
    +
    4479 
    +
    4480 static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
    +
    4481 
    +
    4482 // Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F.
    +
    4483 static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666;
    4484 
    -
    4485 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
    -
    4486  VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
    +
    4485 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC;
    +
    4486 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF;
    4487 
    -
    4488 // Returns number of bits set to 1 in (v).
    -
    4489 static inline uint32_t VmaCountBitsSet(uint32_t v)
    -
    4490 {
    -
    4491  uint32_t c = v - ((v >> 1) & 0x55555555);
    -
    4492  c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
    -
    4493  c = ((c >> 4) + c) & 0x0F0F0F0F;
    -
    4494  c = ((c >> 8) + c) & 0x00FF00FF;
    -
    4495  c = ((c >> 16) + c) & 0x0000FFFF;
    -
    4496  return c;
    -
    4497 }
    -
    4498 
    -
    4499 /*
    -
    4500 Returns true if given number is a power of two.
    -
    4501 T must be unsigned integer number or signed integer but always nonnegative.
    -
    4502 For 0 returns true.
    -
    4503 */
    -
    4504 template <typename T>
    -
    4505 inline bool VmaIsPow2(T x)
    -
    4506 {
    -
    4507  return (x & (x-1)) == 0;
    -
    4508 }
    -
    4509 
    -
    4510 // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
    -
    4511 // Use types like uint32_t, uint64_t as T.
    -
    4512 template <typename T>
    -
    4513 static inline T VmaAlignUp(T val, T alignment)
    -
    4514 {
    -
    4515  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
    -
    4516  return (val + alignment - 1) & ~(alignment - 1);
    -
    4517 }
    -
    4518 // Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8.
    -
    4519 // Use types like uint32_t, uint64_t as T.
    -
    4520 template <typename T>
    -
    4521 static inline T VmaAlignDown(T val, T alignment)
    -
    4522 {
    -
    4523  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
    -
    4524  return val & ~(alignment - 1);
    -
    4525 }
    -
    4526 
    -
    4527 // Division with mathematical rounding to nearest number.
    -
    4528 template <typename T>
    -
    4529 static inline T VmaRoundDiv(T x, T y)
    -
    4530 {
    -
    4531  return (x + (y / (T)2)) / y;
    +
    4488 /*******************************************************************************
    +
    4489 END OF CONFIGURATION
    +
    4490 */
    +
    4491 
    +
    4492 // # Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants.
    +
    4493 
    +
    4494 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040;
    +
    4495 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080;
    +
    4496 static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000;
    +
    4497 
    +
    4498 static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
    +
    4499 
    +
    4500 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
    +
    4501  VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
    +
    4502 
    +
    4503 // Returns number of bits set to 1 in (v).
    +
    4504 static inline uint32_t VmaCountBitsSet(uint32_t v)
    +
    4505 {
    +
    4506  uint32_t c = v - ((v >> 1) & 0x55555555);
    +
    4507  c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
    +
    4508  c = ((c >> 4) + c) & 0x0F0F0F0F;
    +
    4509  c = ((c >> 8) + c) & 0x00FF00FF;
    +
    4510  c = ((c >> 16) + c) & 0x0000FFFF;
    +
    4511  return c;
    +
    4512 }
    +
    4513 
    +
    4514 /*
    +
    4515 Returns true if given number is a power of two.
    +
    4516 T must be unsigned integer number or signed integer but always nonnegative.
    +
    4517 For 0 returns true.
    +
    4518 */
    +
    4519 template <typename T>
    +
    4520 inline bool VmaIsPow2(T x)
    +
    4521 {
    +
    4522  return (x & (x-1)) == 0;
    +
    4523 }
    +
    4524 
    +
    4525 // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
    +
    4526 // Use types like uint32_t, uint64_t as T.
    +
    4527 template <typename T>
    +
    4528 static inline T VmaAlignUp(T val, T alignment)
    +
    4529 {
    +
    4530  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
    +
    4531  return (val + alignment - 1) & ~(alignment - 1);
    4532 }
    -
    4533 
    -
    4534 // Returns smallest power of 2 greater or equal to v.
    -
    4535 static inline uint32_t VmaNextPow2(uint32_t v)
    -
    4536 {
    -
    4537  v--;
    -
    4538  v |= v >> 1;
    -
    4539  v |= v >> 2;
    -
    4540  v |= v >> 4;
    -
    4541  v |= v >> 8;
    -
    4542  v |= v >> 16;
    -
    4543  v++;
    -
    4544  return v;
    -
    4545 }
    -
    4546 static inline uint64_t VmaNextPow2(uint64_t v)
    -
    4547 {
    -
    4548  v--;
    -
    4549  v |= v >> 1;
    -
    4550  v |= v >> 2;
    -
    4551  v |= v >> 4;
    -
    4552  v |= v >> 8;
    -
    4553  v |= v >> 16;
    -
    4554  v |= v >> 32;
    -
    4555  v++;
    -
    4556  return v;
    -
    4557 }
    -
    4558 
    -
    4559 // Returns largest power of 2 less or equal to v.
    -
    4560 static inline uint32_t VmaPrevPow2(uint32_t v)
    -
    4561 {
    -
    4562  v |= v >> 1;
    -
    4563  v |= v >> 2;
    -
    4564  v |= v >> 4;
    -
    4565  v |= v >> 8;
    -
    4566  v |= v >> 16;
    -
    4567  v = v ^ (v >> 1);
    -
    4568  return v;
    -
    4569 }
    -
    4570 static inline uint64_t VmaPrevPow2(uint64_t v)
    -
    4571 {
    -
    4572  v |= v >> 1;
    -
    4573  v |= v >> 2;
    -
    4574  v |= v >> 4;
    -
    4575  v |= v >> 8;
    -
    4576  v |= v >> 16;
    -
    4577  v |= v >> 32;
    -
    4578  v = v ^ (v >> 1);
    -
    4579  return v;
    -
    4580 }
    -
    4581 
    -
    4582 static inline bool VmaStrIsEmpty(const char* pStr)
    -
    4583 {
    -
    4584  return pStr == VMA_NULL || *pStr == '\0';
    -
    4585 }
    -
    4586 
    -
    4587 #if VMA_STATS_STRING_ENABLED
    -
    4588 
    -
    4589 static const char* VmaAlgorithmToStr(uint32_t algorithm)
    -
    4590 {
    -
    4591  switch(algorithm)
    -
    4592  {
    -
    4593  case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT:
    -
    4594  return "Linear";
    -
    4595  case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT:
    -
    4596  return "Buddy";
    -
    4597  case 0:
    -
    4598  return "Default";
    -
    4599  default:
    -
    4600  VMA_ASSERT(0);
    -
    4601  return "";
    -
    4602  }
    -
    4603 }
    -
    4604 
    -
    4605 #endif // #if VMA_STATS_STRING_ENABLED
    -
    4606 
    -
    4607 #ifndef VMA_SORT
    -
    4608 
    -
    4609 template<typename Iterator, typename Compare>
    -
    4610 Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
    -
    4611 {
    -
    4612  Iterator centerValue = end; --centerValue;
    -
    4613  Iterator insertIndex = beg;
    -
    4614  for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex)
    -
    4615  {
    -
    4616  if(cmp(*memTypeIndex, *centerValue))
    -
    4617  {
    -
    4618  if(insertIndex != memTypeIndex)
    -
    4619  {
    -
    4620  VMA_SWAP(*memTypeIndex, *insertIndex);
    -
    4621  }
    -
    4622  ++insertIndex;
    -
    4623  }
    -
    4624  }
    -
    4625  if(insertIndex != centerValue)
    -
    4626  {
    -
    4627  VMA_SWAP(*insertIndex, *centerValue);
    -
    4628  }
    -
    4629  return insertIndex;
    -
    4630 }
    -
    4631 
    -
    4632 template<typename Iterator, typename Compare>
    -
    4633 void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
    -
    4634 {
    -
    4635  if(beg < end)
    -
    4636  {
    -
    4637  Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
    -
    4638  VmaQuickSort<Iterator, Compare>(beg, it, cmp);
    -
    4639  VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
    -
    4640  }
    -
    4641 }
    -
    4642 
    -
    4643 #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp)
    -
    4644 
    -
    4645 #endif // #ifndef VMA_SORT
    +
    4533 // Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8.
    +
    4534 // Use types like uint32_t, uint64_t as T.
    +
    4535 template <typename T>
    +
    4536 static inline T VmaAlignDown(T val, T alignment)
    +
    4537 {
    +
    4538  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
    +
    4539  return val & ~(alignment - 1);
    +
    4540 }
    +
    4541 
    +
    4542 // Division with mathematical rounding to nearest number.
    +
    4543 template <typename T>
    +
    4544 static inline T VmaRoundDiv(T x, T y)
    +
    4545 {
    +
    4546  return (x + (y / (T)2)) / y;
    +
    4547 }
    +
    4548 
    +
    4549 // Returns smallest power of 2 greater or equal to v.
    +
    4550 static inline uint32_t VmaNextPow2(uint32_t v)
    +
    4551 {
    +
    4552  v--;
    +
    4553  v |= v >> 1;
    +
    4554  v |= v >> 2;
    +
    4555  v |= v >> 4;
    +
    4556  v |= v >> 8;
    +
    4557  v |= v >> 16;
    +
    4558  v++;
    +
    4559  return v;
    +
    4560 }
    +
    4561 static inline uint64_t VmaNextPow2(uint64_t v)
    +
    4562 {
    +
    4563  v--;
    +
    4564  v |= v >> 1;
    +
    4565  v |= v >> 2;
    +
    4566  v |= v >> 4;
    +
    4567  v |= v >> 8;
    +
    4568  v |= v >> 16;
    +
    4569  v |= v >> 32;
    +
    4570  v++;
    +
    4571  return v;
    +
    4572 }
    +
    4573 
    +
    4574 // Returns largest power of 2 less or equal to v.
    +
    4575 static inline uint32_t VmaPrevPow2(uint32_t v)
    +
    4576 {
    +
    4577  v |= v >> 1;
    +
    4578  v |= v >> 2;
    +
    4579  v |= v >> 4;
    +
    4580  v |= v >> 8;
    +
    4581  v |= v >> 16;
    +
    4582  v = v ^ (v >> 1);
    +
    4583  return v;
    +
    4584 }
    +
    4585 static inline uint64_t VmaPrevPow2(uint64_t v)
    +
    4586 {
    +
    4587  v |= v >> 1;
    +
    4588  v |= v >> 2;
    +
    4589  v |= v >> 4;
    +
    4590  v |= v >> 8;
    +
    4591  v |= v >> 16;
    +
    4592  v |= v >> 32;
    +
    4593  v = v ^ (v >> 1);
    +
    4594  return v;
    +
    4595 }
    +
    4596 
    +
    4597 static inline bool VmaStrIsEmpty(const char* pStr)
    +
    4598 {
    +
    4599  return pStr == VMA_NULL || *pStr == '\0';
    +
    4600 }
    +
    4601 
    +
    4602 #if VMA_STATS_STRING_ENABLED
    +
    4603 
    +
    4604 static const char* VmaAlgorithmToStr(uint32_t algorithm)
    +
    4605 {
    +
    4606  switch(algorithm)
    +
    4607  {
    +
    4608  case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT:
    +
    4609  return "Linear";
    +
    4610  case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT:
    +
    4611  return "Buddy";
    +
    4612  case 0:
    +
    4613  return "Default";
    +
    4614  default:
    +
    4615  VMA_ASSERT(0);
    +
    4616  return "";
    +
    4617  }
    +
    4618 }
    +
    4619 
    +
    4620 #endif // #if VMA_STATS_STRING_ENABLED
    +
    4621 
    +
    4622 #ifndef VMA_SORT
    +
    4623 
    +
    4624 template<typename Iterator, typename Compare>
    +
    4625 Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
    +
    4626 {
    +
    4627  Iterator centerValue = end; --centerValue;
    +
    4628  Iterator insertIndex = beg;
    +
    4629  for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex)
    +
    4630  {
    +
    4631  if(cmp(*memTypeIndex, *centerValue))
    +
    4632  {
    +
    4633  if(insertIndex != memTypeIndex)
    +
    4634  {
    +
    4635  VMA_SWAP(*memTypeIndex, *insertIndex);
    +
    4636  }
    +
    4637  ++insertIndex;
    +
    4638  }
    +
    4639  }
    +
    4640  if(insertIndex != centerValue)
    +
    4641  {
    +
    4642  VMA_SWAP(*insertIndex, *centerValue);
    +
    4643  }
    +
    4644  return insertIndex;
    +
    4645 }
    4646 
    -
    4647 /*
    -
    4648 Returns true if two memory blocks occupy overlapping pages.
    -
    4649 ResourceA must be in less memory offset than ResourceB.
    -
    4650 
    -
    4651 Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
    -
    4652 chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
    -
    4653 */
    -
    4654 static inline bool VmaBlocksOnSamePage(
    -
    4655  VkDeviceSize resourceAOffset,
    -
    4656  VkDeviceSize resourceASize,
    -
    4657  VkDeviceSize resourceBOffset,
    -
    4658  VkDeviceSize pageSize)
    -
    4659 {
    -
    4660  VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
    -
    4661  VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
    -
    4662  VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
    -
    4663  VkDeviceSize resourceBStart = resourceBOffset;
    -
    4664  VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
    -
    4665  return resourceAEndPage == resourceBStartPage;
    -
    4666 }
    -
    4667 
    -
    4668 enum VmaSuballocationType
    -
    4669 {
    -
    4670  VMA_SUBALLOCATION_TYPE_FREE = 0,
    -
    4671  VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
    -
    4672  VMA_SUBALLOCATION_TYPE_BUFFER = 2,
    -
    4673  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
    -
    4674  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
    -
    4675  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
    -
    4676  VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
    -
    4677 };
    -
    4678 
    -
    4679 /*
    -
    4680 Returns true if given suballocation types could conflict and must respect
    -
    4681 VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
    -
    4682 or linear image and another one is optimal image. If type is unknown, behave
    -
    4683 conservatively.
    -
    4684 */
    -
    4685 static inline bool VmaIsBufferImageGranularityConflict(
    -
    4686  VmaSuballocationType suballocType1,
    -
    4687  VmaSuballocationType suballocType2)
    -
    4688 {
    -
    4689  if(suballocType1 > suballocType2)
    -
    4690  {
    -
    4691  VMA_SWAP(suballocType1, suballocType2);
    -
    4692  }
    +
    4647 template<typename Iterator, typename Compare>
    +
    4648 void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
    +
    4649 {
    +
    4650  if(beg < end)
    +
    4651  {
    +
    4652  Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
    +
    4653  VmaQuickSort<Iterator, Compare>(beg, it, cmp);
    +
    4654  VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
    +
    4655  }
    +
    4656 }
    +
    4657 
    +
    4658 #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp)
    +
    4659 
    +
    4660 #endif // #ifndef VMA_SORT
    +
    4661 
    +
    4662 /*
    +
    4663 Returns true if two memory blocks occupy overlapping pages.
    +
    4664 ResourceA must be in less memory offset than ResourceB.
    +
    4665 
    +
    4666 Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
    +
    4667 chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
    +
    4668 */
    +
    4669 static inline bool VmaBlocksOnSamePage(
    +
    4670  VkDeviceSize resourceAOffset,
    +
    4671  VkDeviceSize resourceASize,
    +
    4672  VkDeviceSize resourceBOffset,
    +
    4673  VkDeviceSize pageSize)
    +
    4674 {
    +
    4675  VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
    +
    4676  VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
    +
    4677  VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
    +
    4678  VkDeviceSize resourceBStart = resourceBOffset;
    +
    4679  VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
    +
    4680  return resourceAEndPage == resourceBStartPage;
    +
    4681 }
    +
    4682 
    +
    4683 enum VmaSuballocationType
    +
    4684 {
    +
    4685  VMA_SUBALLOCATION_TYPE_FREE = 0,
    +
    4686  VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
    +
    4687  VMA_SUBALLOCATION_TYPE_BUFFER = 2,
    +
    4688  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
    +
    4689  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
    +
    4690  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
    +
    4691  VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
    +
    4692 };
    4693 
    -
    4694  switch(suballocType1)
    -
    4695  {
    -
    4696  case VMA_SUBALLOCATION_TYPE_FREE:
    -
    4697  return false;
    -
    4698  case VMA_SUBALLOCATION_TYPE_UNKNOWN:
    -
    4699  return true;
    -
    4700  case VMA_SUBALLOCATION_TYPE_BUFFER:
    -
    4701  return
    -
    4702  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    -
    4703  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    -
    4704  case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
    -
    4705  return
    -
    4706  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    -
    4707  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
    -
    4708  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    -
    4709  case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
    -
    4710  return
    -
    4711  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    -
    4712  case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
    -
    4713  return false;
    -
    4714  default:
    -
    4715  VMA_ASSERT(0);
    -
    4716  return true;
    -
    4717  }
    -
    4718 }
    -
    4719 
    -
    4720 static void VmaWriteMagicValue(void* pData, VkDeviceSize offset)
    -
    4721 {
    -
    4722 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
    -
    4723  uint32_t* pDst = (uint32_t*)((char*)pData + offset);
    -
    4724  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
    -
    4725  for(size_t i = 0; i < numberCount; ++i, ++pDst)
    -
    4726  {
    -
    4727  *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE;
    -
    4728  }
    -
    4729 #else
    -
    4730  // no-op
    -
    4731 #endif
    -
    4732 }
    -
    4733 
    -
    4734 static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset)
    -
    4735 {
    -
    4736 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
    -
    4737  const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset);
    -
    4738  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
    -
    4739  for(size_t i = 0; i < numberCount; ++i, ++pSrc)
    -
    4740  {
    -
    4741  if(*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE)
    -
    4742  {
    -
    4743  return false;
    -
    4744  }
    -
    4745  }
    +
    4694 /*
    +
    4695 Returns true if given suballocation types could conflict and must respect
    +
    4696 VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
    +
    4697 or linear image and another one is optimal image. If type is unknown, behave
    +
    4698 conservatively.
    +
    4699 */
    +
    4700 static inline bool VmaIsBufferImageGranularityConflict(
    +
    4701  VmaSuballocationType suballocType1,
    +
    4702  VmaSuballocationType suballocType2)
    +
    4703 {
    +
    4704  if(suballocType1 > suballocType2)
    +
    4705  {
    +
    4706  VMA_SWAP(suballocType1, suballocType2);
    +
    4707  }
    +
    4708 
    +
    4709  switch(suballocType1)
    +
    4710  {
    +
    4711  case VMA_SUBALLOCATION_TYPE_FREE:
    +
    4712  return false;
    +
    4713  case VMA_SUBALLOCATION_TYPE_UNKNOWN:
    +
    4714  return true;
    +
    4715  case VMA_SUBALLOCATION_TYPE_BUFFER:
    +
    4716  return
    +
    4717  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    +
    4718  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    +
    4719  case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
    +
    4720  return
    +
    4721  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    +
    4722  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
    +
    4723  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    +
    4724  case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
    +
    4725  return
    +
    4726  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    +
    4727  case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
    +
    4728  return false;
    +
    4729  default:
    +
    4730  VMA_ASSERT(0);
    +
    4731  return true;
    +
    4732  }
    +
    4733 }
    +
    4734 
    +
    4735 static void VmaWriteMagicValue(void* pData, VkDeviceSize offset)
    +
    4736 {
    +
    4737 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
    +
    4738  uint32_t* pDst = (uint32_t*)((char*)pData + offset);
    +
    4739  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
    +
    4740  for(size_t i = 0; i < numberCount; ++i, ++pDst)
    +
    4741  {
    +
    4742  *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE;
    +
    4743  }
    +
    4744 #else
    +
    4745  // no-op
    4746 #endif
    -
    4747  return true;
    -
    4748 }
    -
    4749 
    -
    4750 /*
    -
    4751 Fills structure with parameters of an example buffer to be used for transfers
    -
    4752 during GPU memory defragmentation.
    -
    4753 */
    -
    4754 static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo)
    -
    4755 {
    -
    4756  memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo));
    -
    4757  outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    -
    4758  outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
    -
    4759  outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size.
    -
    4760 }
    -
    4761 
    -
    4762 // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
    -
    4763 struct VmaMutexLock
    -
    4764 {
    -
    4765  VMA_CLASS_NO_COPY(VmaMutexLock)
    -
    4766 public:
    -
    4767  VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) :
    -
    4768  m_pMutex(useMutex ? &mutex : VMA_NULL)
    -
    4769  { if(m_pMutex) { m_pMutex->Lock(); } }
    -
    4770  ~VmaMutexLock()
    -
    4771  { if(m_pMutex) { m_pMutex->Unlock(); } }
    -
    4772 private:
    -
    4773  VMA_MUTEX* m_pMutex;
    -
    4774 };
    -
    4775 
    -
    4776 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
    -
    4777 struct VmaMutexLockRead
    -
    4778 {
    -
    4779  VMA_CLASS_NO_COPY(VmaMutexLockRead)
    -
    4780 public:
    -
    4781  VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) :
    -
    4782  m_pMutex(useMutex ? &mutex : VMA_NULL)
    -
    4783  { if(m_pMutex) { m_pMutex->LockRead(); } }
    -
    4784  ~VmaMutexLockRead() { if(m_pMutex) { m_pMutex->UnlockRead(); } }
    -
    4785 private:
    -
    4786  VMA_RW_MUTEX* m_pMutex;
    -
    4787 };
    -
    4788 
    -
    4789 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
    -
    4790 struct VmaMutexLockWrite
    -
    4791 {
    -
    4792  VMA_CLASS_NO_COPY(VmaMutexLockWrite)
    -
    4793 public:
    -
    4794  VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) :
    -
    4795  m_pMutex(useMutex ? &mutex : VMA_NULL)
    -
    4796  { if(m_pMutex) { m_pMutex->LockWrite(); } }
    -
    4797  ~VmaMutexLockWrite() { if(m_pMutex) { m_pMutex->UnlockWrite(); } }
    -
    4798 private:
    -
    4799  VMA_RW_MUTEX* m_pMutex;
    -
    4800 };
    -
    4801 
    -
    4802 #if VMA_DEBUG_GLOBAL_MUTEX
    -
    4803  static VMA_MUTEX gDebugGlobalMutex;
    -
    4804  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true);
    -
    4805 #else
    -
    4806  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    4807 #endif
    -
    4808 
    -
    4809 // Minimum size of a free suballocation to register it in the free suballocation collection.
    -
    4810 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
    -
    4811 
    -
    4812 /*
    -
    4813 Performs binary search and returns iterator to first element that is greater or
    -
    4814 equal to (key), according to comparison (cmp).
    -
    4815 
    -
    4816 Cmp should return true if first argument is less than second argument.
    -
    4817 
    -
    4818 Returned value is the found element, if present in the collection or place where
    -
    4819 new element with value (key) should be inserted.
    -
    4820 */
    -
    4821 template <typename CmpLess, typename IterT, typename KeyT>
    -
    4822 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, const CmpLess& cmp)
    -
    4823 {
    -
    4824  size_t down = 0, up = (end - beg);
    -
    4825  while(down < up)
    -
    4826  {
    -
    4827  const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation
    -
    4828  if(cmp(*(beg+mid), key))
    -
    4829  {
    -
    4830  down = mid + 1;
    -
    4831  }
    -
    4832  else
    -
    4833  {
    -
    4834  up = mid;
    -
    4835  }
    -
    4836  }
    -
    4837  return beg + down;
    -
    4838 }
    -
    4839 
    -
    4840 template<typename CmpLess, typename IterT, typename KeyT>
    -
    4841 IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
    -
    4842 {
    -
    4843  IterT it = VmaBinaryFindFirstNotLess<CmpLess, IterT, KeyT>(
    -
    4844  beg, end, value, cmp);
    -
    4845  if(it == end ||
    -
    4846  (!cmp(*it, value) && !cmp(value, *it)))
    -
    4847  {
    -
    4848  return it;
    -
    4849  }
    -
    4850  return end;
    -
    4851 }
    -
    4852 
    -
    4853 /*
    -
    4854 Returns true if all pointers in the array are not-null and unique.
    -
    4855 Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
    -
    4856 T must be pointer type, e.g. VmaAllocation, VmaPool.
    -
    4857 */
    -
    4858 template<typename T>
    -
    4859 static bool VmaValidatePointerArray(uint32_t count, const T* arr)
    -
    4860 {
    -
    4861  for(uint32_t i = 0; i < count; ++i)
    +
    4747 }
    +
    4748 
    +
    4749 static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset)
    +
    4750 {
    +
    4751 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
    +
    4752  const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset);
    +
    4753  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
    +
    4754  for(size_t i = 0; i < numberCount; ++i, ++pSrc)
    +
    4755  {
    +
    4756  if(*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE)
    +
    4757  {
    +
    4758  return false;
    +
    4759  }
    +
    4760  }
    +
    4761 #endif
    +
    4762  return true;
    +
    4763 }
    +
    4764 
    +
    4765 /*
    +
    4766 Fills structure with parameters of an example buffer to be used for transfers
    +
    4767 during GPU memory defragmentation.
    +
    4768 */
    +
    4769 static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo)
    +
    4770 {
    +
    4771  memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo));
    +
    4772  outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    +
    4773  outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
    +
    4774  outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size.
    +
    4775 }
    +
    4776 
    +
    4777 // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
    +
    4778 struct VmaMutexLock
    +
    4779 {
    +
    4780  VMA_CLASS_NO_COPY(VmaMutexLock)
    +
    4781 public:
    +
    4782  VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) :
    +
    4783  m_pMutex(useMutex ? &mutex : VMA_NULL)
    +
    4784  { if(m_pMutex) { m_pMutex->Lock(); } }
    +
    4785  ~VmaMutexLock()
    +
    4786  { if(m_pMutex) { m_pMutex->Unlock(); } }
    +
    4787 private:
    +
    4788  VMA_MUTEX* m_pMutex;
    +
    4789 };
    +
    4790 
    +
    4791 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
    +
    4792 struct VmaMutexLockRead
    +
    4793 {
    +
    4794  VMA_CLASS_NO_COPY(VmaMutexLockRead)
    +
    4795 public:
    +
    4796  VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) :
    +
    4797  m_pMutex(useMutex ? &mutex : VMA_NULL)
    +
    4798  { if(m_pMutex) { m_pMutex->LockRead(); } }
    +
    4799  ~VmaMutexLockRead() { if(m_pMutex) { m_pMutex->UnlockRead(); } }
    +
    4800 private:
    +
    4801  VMA_RW_MUTEX* m_pMutex;
    +
    4802 };
    +
    4803 
    +
    4804 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
    +
    4805 struct VmaMutexLockWrite
    +
    4806 {
    +
    4807  VMA_CLASS_NO_COPY(VmaMutexLockWrite)
    +
    4808 public:
    +
    4809  VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) :
    +
    4810  m_pMutex(useMutex ? &mutex : VMA_NULL)
    +
    4811  { if(m_pMutex) { m_pMutex->LockWrite(); } }
    +
    4812  ~VmaMutexLockWrite() { if(m_pMutex) { m_pMutex->UnlockWrite(); } }
    +
    4813 private:
    +
    4814  VMA_RW_MUTEX* m_pMutex;
    +
    4815 };
    +
    4816 
    +
    4817 #if VMA_DEBUG_GLOBAL_MUTEX
    +
    4818  static VMA_MUTEX gDebugGlobalMutex;
    +
    4819  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true);
    +
    4820 #else
    +
    4821  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    4822 #endif
    +
    4823 
    +
    4824 // Minimum size of a free suballocation to register it in the free suballocation collection.
    +
    4825 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
    +
    4826 
    +
    4827 /*
    +
    4828 Performs binary search and returns iterator to first element that is greater or
    +
    4829 equal to (key), according to comparison (cmp).
    +
    4830 
    +
    4831 Cmp should return true if first argument is less than second argument.
    +
    4832 
    +
    4833 Returned value is the found element, if present in the collection or place where
    +
    4834 new element with value (key) should be inserted.
    +
    4835 */
    +
    4836 template <typename CmpLess, typename IterT, typename KeyT>
    +
    4837 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, const CmpLess& cmp)
    +
    4838 {
    +
    4839  size_t down = 0, up = (end - beg);
    +
    4840  while(down < up)
    +
    4841  {
    +
    4842  const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation
    +
    4843  if(cmp(*(beg+mid), key))
    +
    4844  {
    +
    4845  down = mid + 1;
    +
    4846  }
    +
    4847  else
    +
    4848  {
    +
    4849  up = mid;
    +
    4850  }
    +
    4851  }
    +
    4852  return beg + down;
    +
    4853 }
    +
    4854 
    +
    4855 template<typename CmpLess, typename IterT, typename KeyT>
    +
    4856 IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
    +
    4857 {
    +
    4858  IterT it = VmaBinaryFindFirstNotLess<CmpLess, IterT, KeyT>(
    +
    4859  beg, end, value, cmp);
    +
    4860  if(it == end ||
    +
    4861  (!cmp(*it, value) && !cmp(value, *it)))
    4862  {
    -
    4863  const T iPtr = arr[i];
    -
    4864  if(iPtr == VMA_NULL)
    -
    4865  {
    -
    4866  return false;
    -
    4867  }
    -
    4868  for(uint32_t j = i + 1; j < count; ++j)
    -
    4869  {
    -
    4870  if(iPtr == arr[j])
    -
    4871  {
    -
    4872  return false;
    -
    4873  }
    -
    4874  }
    -
    4875  }
    -
    4876  return true;
    -
    4877 }
    -
    4878 
    -
    4879 template<typename MainT, typename NewT>
    -
    4880 static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct)
    -
    4881 {
    -
    4882  newStruct->pNext = mainStruct->pNext;
    -
    4883  mainStruct->pNext = newStruct;
    -
    4884 }
    -
    4885 
    -
    4887 // Memory allocation
    -
    4888 
    -
    4889 static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
    -
    4890 {
    -
    4891  void* result = VMA_NULL;
    -
    4892  if((pAllocationCallbacks != VMA_NULL) &&
    -
    4893  (pAllocationCallbacks->pfnAllocation != VMA_NULL))
    -
    4894  {
    -
    4895  result = (*pAllocationCallbacks->pfnAllocation)(
    -
    4896  pAllocationCallbacks->pUserData,
    -
    4897  size,
    -
    4898  alignment,
    -
    4899  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    -
    4900  }
    -
    4901  else
    -
    4902  {
    -
    4903  result = VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
    -
    4904  }
    -
    4905  VMA_ASSERT(result != VMA_NULL && "CPU memory allocation failed.");
    -
    4906  return result;
    -
    4907 }
    -
    4908 
    -
    4909 static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
    -
    4910 {
    -
    4911  if((pAllocationCallbacks != VMA_NULL) &&
    -
    4912  (pAllocationCallbacks->pfnFree != VMA_NULL))
    -
    4913  {
    -
    4914  (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
    +
    4863  return it;
    +
    4864  }
    +
    4865  return end;
    +
    4866 }
    +
    4867 
    +
    4868 /*
    +
    4869 Returns true if all pointers in the array are not-null and unique.
    +
    4870 Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
    +
    4871 T must be pointer type, e.g. VmaAllocation, VmaPool.
    +
    4872 */
    +
    4873 template<typename T>
    +
    4874 static bool VmaValidatePointerArray(uint32_t count, const T* arr)
    +
    4875 {
    +
    4876  for(uint32_t i = 0; i < count; ++i)
    +
    4877  {
    +
    4878  const T iPtr = arr[i];
    +
    4879  if(iPtr == VMA_NULL)
    +
    4880  {
    +
    4881  return false;
    +
    4882  }
    +
    4883  for(uint32_t j = i + 1; j < count; ++j)
    +
    4884  {
    +
    4885  if(iPtr == arr[j])
    +
    4886  {
    +
    4887  return false;
    +
    4888  }
    +
    4889  }
    +
    4890  }
    +
    4891  return true;
    +
    4892 }
    +
    4893 
    +
    4894 template<typename MainT, typename NewT>
    +
    4895 static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct)
    +
    4896 {
    +
    4897  newStruct->pNext = mainStruct->pNext;
    +
    4898  mainStruct->pNext = newStruct;
    +
    4899 }
    +
    4900 
    +
    4902 // Memory allocation
    +
    4903 
    +
    4904 static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
    +
    4905 {
    +
    4906  void* result = VMA_NULL;
    +
    4907  if((pAllocationCallbacks != VMA_NULL) &&
    +
    4908  (pAllocationCallbacks->pfnAllocation != VMA_NULL))
    +
    4909  {
    +
    4910  result = (*pAllocationCallbacks->pfnAllocation)(
    +
    4911  pAllocationCallbacks->pUserData,
    +
    4912  size,
    +
    4913  alignment,
    +
    4914  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    4915  }
    4916  else
    4917  {
    -
    4918  VMA_SYSTEM_ALIGNED_FREE(ptr);
    +
    4918  result = VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
    4919  }
    -
    4920 }
    -
    4921 
    -
    4922 template<typename T>
    -
    4923 static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
    -
    4924 {
    -
    4925  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
    -
    4926 }
    -
    4927 
    -
    4928 template<typename T>
    -
    4929 static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
    -
    4930 {
    -
    4931  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
    -
    4932 }
    -
    4933 
    -
    4934 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
    -
    4935 
    -
    4936 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
    -
    4937 
    -
    4938 template<typename T>
    -
    4939 static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
    -
    4940 {
    -
    4941  ptr->~T();
    -
    4942  VmaFree(pAllocationCallbacks, ptr);
    -
    4943 }
    -
    4944 
    -
    4945 template<typename T>
    -
    4946 static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
    -
    4947 {
    -
    4948  if(ptr != VMA_NULL)
    -
    4949  {
    -
    4950  for(size_t i = count; i--; )
    -
    4951  {
    -
    4952  ptr[i].~T();
    -
    4953  }
    -
    4954  VmaFree(pAllocationCallbacks, ptr);
    -
    4955  }
    -
    4956 }
    -
    4957 
    -
    4958 static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr)
    -
    4959 {
    -
    4960  if(srcStr != VMA_NULL)
    -
    4961  {
    -
    4962  const size_t len = strlen(srcStr);
    -
    4963  char* const result = vma_new_array(allocs, char, len + 1);
    -
    4964  memcpy(result, srcStr, len + 1);
    -
    4965  return result;
    -
    4966  }
    -
    4967  else
    -
    4968  {
    -
    4969  return VMA_NULL;
    +
    4920  VMA_ASSERT(result != VMA_NULL && "CPU memory allocation failed.");
    +
    4921  return result;
    +
    4922 }
    +
    4923 
    +
    4924 static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
    +
    4925 {
    +
    4926  if((pAllocationCallbacks != VMA_NULL) &&
    +
    4927  (pAllocationCallbacks->pfnFree != VMA_NULL))
    +
    4928  {
    +
    4929  (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
    +
    4930  }
    +
    4931  else
    +
    4932  {
    +
    4933  VMA_SYSTEM_ALIGNED_FREE(ptr);
    +
    4934  }
    +
    4935 }
    +
    4936 
    +
    4937 template<typename T>
    +
    4938 static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
    +
    4939 {
    +
    4940  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
    +
    4941 }
    +
    4942 
    +
    4943 template<typename T>
    +
    4944 static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
    +
    4945 {
    +
    4946  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
    +
    4947 }
    +
    4948 
    +
    4949 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
    +
    4950 
    +
    4951 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
    +
    4952 
    +
    4953 template<typename T>
    +
    4954 static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
    +
    4955 {
    +
    4956  ptr->~T();
    +
    4957  VmaFree(pAllocationCallbacks, ptr);
    +
    4958 }
    +
    4959 
    +
    4960 template<typename T>
    +
    4961 static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
    +
    4962 {
    +
    4963  if(ptr != VMA_NULL)
    +
    4964  {
    +
    4965  for(size_t i = count; i--; )
    +
    4966  {
    +
    4967  ptr[i].~T();
    +
    4968  }
    +
    4969  VmaFree(pAllocationCallbacks, ptr);
    4970  }
    4971 }
    4972 
    -
    4973 static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str)
    +
    4973 static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr)
    4974 {
    -
    4975  if(str != VMA_NULL)
    +
    4975  if(srcStr != VMA_NULL)
    4976  {
    -
    4977  const size_t len = strlen(str);
    -
    4978  vma_delete_array(allocs, str, len + 1);
    -
    4979  }
    -
    4980 }
    -
    4981 
    -
    4982 // STL-compatible allocator.
    -
    4983 template<typename T>
    -
    4984 class VmaStlAllocator
    -
    4985 {
    -
    4986 public:
    -
    4987  const VkAllocationCallbacks* const m_pCallbacks;
    -
    4988  typedef T value_type;
    -
    4989 
    -
    4990  VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
    -
    4991  template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
    -
    4992 
    -
    4993  T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
    -
    4994  void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
    -
    4995 
    -
    4996  template<typename U>
    -
    4997  bool operator==(const VmaStlAllocator<U>& rhs) const
    -
    4998  {
    -
    4999  return m_pCallbacks == rhs.m_pCallbacks;
    -
    5000  }
    -
    5001  template<typename U>
    -
    5002  bool operator!=(const VmaStlAllocator<U>& rhs) const
    -
    5003  {
    -
    5004  return m_pCallbacks != rhs.m_pCallbacks;
    -
    5005  }
    -
    5006 
    -
    5007  VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
    -
    5008  VmaStlAllocator(const VmaStlAllocator&) = default;
    -
    5009 };
    +
    4977  const size_t len = strlen(srcStr);
    +
    4978  char* const result = vma_new_array(allocs, char, len + 1);
    +
    4979  memcpy(result, srcStr, len + 1);
    +
    4980  return result;
    +
    4981  }
    +
    4982  else
    +
    4983  {
    +
    4984  return VMA_NULL;
    +
    4985  }
    +
    4986 }
    +
    4987 
    +
    4988 static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str)
    +
    4989 {
    +
    4990  if(str != VMA_NULL)
    +
    4991  {
    +
    4992  const size_t len = strlen(str);
    +
    4993  vma_delete_array(allocs, str, len + 1);
    +
    4994  }
    +
    4995 }
    +
    4996 
    +
    4997 // STL-compatible allocator.
    +
    4998 template<typename T>
    +
    4999 class VmaStlAllocator
    +
    5000 {
    +
    5001 public:
    +
    5002  const VkAllocationCallbacks* const m_pCallbacks;
    +
    5003  typedef T value_type;
    +
    5004 
    +
    5005  VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
    +
    5006  template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
    +
    5007 
    +
    5008  T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
    +
    5009  void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
    5010 
    -
    5011 #if VMA_USE_STL_VECTOR
    -
    5012 
    -
    5013 #define VmaVector std::vector
    -
    5014 
    -
    5015 template<typename T, typename allocatorT>
    -
    5016 static void VmaVectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
    -
    5017 {
    -
    5018  vec.insert(vec.begin() + index, item);
    -
    5019 }
    -
    5020 
    -
    5021 template<typename T, typename allocatorT>
    -
    5022 static void VmaVectorRemove(std::vector<T, allocatorT>& vec, size_t index)
    -
    5023 {
    -
    5024  vec.erase(vec.begin() + index);
    -
    5025 }
    -
    5026 
    -
    5027 #else // #if VMA_USE_STL_VECTOR
    -
    5028 
    -
    5029 /* Class with interface compatible with subset of std::vector.
    -
    5030 T must be POD because constructors and destructors are not called and memcpy is
    -
    5031 used for these objects. */
    -
    5032 template<typename T, typename AllocatorT>
    -
    5033 class VmaVector
    -
    5034 {
    -
    5035 public:
    -
    5036  typedef T value_type;
    -
    5037 
    -
    5038  VmaVector(const AllocatorT& allocator) :
    -
    5039  m_Allocator(allocator),
    -
    5040  m_pArray(VMA_NULL),
    -
    5041  m_Count(0),
    -
    5042  m_Capacity(0)
    -
    5043  {
    -
    5044  }
    -
    5045 
    -
    5046  VmaVector(size_t count, const AllocatorT& allocator) :
    -
    5047  m_Allocator(allocator),
    -
    5048  m_pArray(count ? (T*)VmaAllocateArray<T>(allocator.m_pCallbacks, count) : VMA_NULL),
    -
    5049  m_Count(count),
    -
    5050  m_Capacity(count)
    -
    5051  {
    -
    5052  }
    -
    5053 
    -
    5054  // This version of the constructor is here for compatibility with pre-C++14 std::vector.
    -
    5055  // value is unused.
    -
    5056  VmaVector(size_t count, const T& value, const AllocatorT& allocator)
    -
    5057  : VmaVector(count, allocator) {}
    -
    5058 
    -
    5059  VmaVector(const VmaVector<T, AllocatorT>& src) :
    -
    5060  m_Allocator(src.m_Allocator),
    -
    5061  m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL),
    -
    5062  m_Count(src.m_Count),
    -
    5063  m_Capacity(src.m_Count)
    -
    5064  {
    -
    5065  if(m_Count != 0)
    -
    5066  {
    -
    5067  memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
    -
    5068  }
    -
    5069  }
    -
    5070 
    -
    5071  ~VmaVector()
    -
    5072  {
    -
    5073  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    -
    5074  }
    -
    5075 
    -
    5076  VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
    -
    5077  {
    -
    5078  if(&rhs != this)
    -
    5079  {
    -
    5080  resize(rhs.m_Count);
    -
    5081  if(m_Count != 0)
    -
    5082  {
    -
    5083  memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
    -
    5084  }
    -
    5085  }
    -
    5086  return *this;
    -
    5087  }
    -
    5088 
    -
    5089  bool empty() const { return m_Count == 0; }
    -
    5090  size_t size() const { return m_Count; }
    -
    5091  T* data() { return m_pArray; }
    -
    5092  const T* data() const { return m_pArray; }
    -
    5093 
    -
    5094  T& operator[](size_t index)
    -
    5095  {
    -
    5096  VMA_HEAVY_ASSERT(index < m_Count);
    -
    5097  return m_pArray[index];
    -
    5098  }
    -
    5099  const T& operator[](size_t index) const
    -
    5100  {
    -
    5101  VMA_HEAVY_ASSERT(index < m_Count);
    -
    5102  return m_pArray[index];
    -
    5103  }
    -
    5104 
    -
    5105  T& front()
    -
    5106  {
    -
    5107  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5108  return m_pArray[0];
    -
    5109  }
    -
    5110  const T& front() const
    -
    5111  {
    -
    5112  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5113  return m_pArray[0];
    -
    5114  }
    -
    5115  T& back()
    -
    5116  {
    -
    5117  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5118  return m_pArray[m_Count - 1];
    -
    5119  }
    -
    5120  const T& back() const
    -
    5121  {
    +
    5011  template<typename U>
    +
    5012  bool operator==(const VmaStlAllocator<U>& rhs) const
    +
    5013  {
    +
    5014  return m_pCallbacks == rhs.m_pCallbacks;
    +
    5015  }
    +
    5016  template<typename U>
    +
    5017  bool operator!=(const VmaStlAllocator<U>& rhs) const
    +
    5018  {
    +
    5019  return m_pCallbacks != rhs.m_pCallbacks;
    +
    5020  }
    +
    5021 
    +
    5022  VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
    +
    5023  VmaStlAllocator(const VmaStlAllocator&) = default;
    +
    5024 };
    +
    5025 
    +
    5026 #if VMA_USE_STL_VECTOR
    +
    5027 
    +
    5028 #define VmaVector std::vector
    +
    5029 
    +
    5030 template<typename T, typename allocatorT>
    +
    5031 static void VmaVectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
    +
    5032 {
    +
    5033  vec.insert(vec.begin() + index, item);
    +
    5034 }
    +
    5035 
    +
    5036 template<typename T, typename allocatorT>
    +
    5037 static void VmaVectorRemove(std::vector<T, allocatorT>& vec, size_t index)
    +
    5038 {
    +
    5039  vec.erase(vec.begin() + index);
    +
    5040 }
    +
    5041 
    +
    5042 #else // #if VMA_USE_STL_VECTOR
    +
    5043 
    +
    5044 /* Class with interface compatible with subset of std::vector.
    +
    5045 T must be POD because constructors and destructors are not called and memcpy is
    +
    5046 used for these objects. */
    +
    5047 template<typename T, typename AllocatorT>
    +
    5048 class VmaVector
    +
    5049 {
    +
    5050 public:
    +
    5051  typedef T value_type;
    +
    5052 
    +
    5053  VmaVector(const AllocatorT& allocator) :
    +
    5054  m_Allocator(allocator),
    +
    5055  m_pArray(VMA_NULL),
    +
    5056  m_Count(0),
    +
    5057  m_Capacity(0)
    +
    5058  {
    +
    5059  }
    +
    5060 
    +
    5061  VmaVector(size_t count, const AllocatorT& allocator) :
    +
    5062  m_Allocator(allocator),
    +
    5063  m_pArray(count ? (T*)VmaAllocateArray<T>(allocator.m_pCallbacks, count) : VMA_NULL),
    +
    5064  m_Count(count),
    +
    5065  m_Capacity(count)
    +
    5066  {
    +
    5067  }
    +
    5068 
    +
    5069  // This version of the constructor is here for compatibility with pre-C++14 std::vector.
    +
    5070  // value is unused.
    +
    5071  VmaVector(size_t count, const T& value, const AllocatorT& allocator)
    +
    5072  : VmaVector(count, allocator) {}
    +
    5073 
    +
    5074  VmaVector(const VmaVector<T, AllocatorT>& src) :
    +
    5075  m_Allocator(src.m_Allocator),
    +
    5076  m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL),
    +
    5077  m_Count(src.m_Count),
    +
    5078  m_Capacity(src.m_Count)
    +
    5079  {
    +
    5080  if(m_Count != 0)
    +
    5081  {
    +
    5082  memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
    +
    5083  }
    +
    5084  }
    +
    5085 
    +
    5086  ~VmaVector()
    +
    5087  {
    +
    5088  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    +
    5089  }
    +
    5090 
    +
    5091  VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
    +
    5092  {
    +
    5093  if(&rhs != this)
    +
    5094  {
    +
    5095  resize(rhs.m_Count);
    +
    5096  if(m_Count != 0)
    +
    5097  {
    +
    5098  memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
    +
    5099  }
    +
    5100  }
    +
    5101  return *this;
    +
    5102  }
    +
    5103 
    +
    5104  bool empty() const { return m_Count == 0; }
    +
    5105  size_t size() const { return m_Count; }
    +
    5106  T* data() { return m_pArray; }
    +
    5107  const T* data() const { return m_pArray; }
    +
    5108 
    +
    5109  T& operator[](size_t index)
    +
    5110  {
    +
    5111  VMA_HEAVY_ASSERT(index < m_Count);
    +
    5112  return m_pArray[index];
    +
    5113  }
    +
    5114  const T& operator[](size_t index) const
    +
    5115  {
    +
    5116  VMA_HEAVY_ASSERT(index < m_Count);
    +
    5117  return m_pArray[index];
    +
    5118  }
    +
    5119 
    +
    5120  T& front()
    +
    5121  {
    5122  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5123  return m_pArray[m_Count - 1];
    +
    5123  return m_pArray[0];
    5124  }
    -
    5125 
    -
    5126  void reserve(size_t newCapacity, bool freeMemory = false)
    -
    5127  {
    -
    5128  newCapacity = VMA_MAX(newCapacity, m_Count);
    -
    5129 
    -
    5130  if((newCapacity < m_Capacity) && !freeMemory)
    -
    5131  {
    -
    5132  newCapacity = m_Capacity;
    -
    5133  }
    -
    5134 
    -
    5135  if(newCapacity != m_Capacity)
    -
    5136  {
    -
    5137  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
    -
    5138  if(m_Count != 0)
    -
    5139  {
    -
    5140  memcpy(newArray, m_pArray, m_Count * sizeof(T));
    -
    5141  }
    -
    5142  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    -
    5143  m_Capacity = newCapacity;
    -
    5144  m_pArray = newArray;
    -
    5145  }
    -
    5146  }
    -
    5147 
    -
    5148  void resize(size_t newCount)
    -
    5149  {
    -
    5150  size_t newCapacity = m_Capacity;
    -
    5151  if(newCount > m_Capacity)
    -
    5152  {
    -
    5153  newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
    -
    5154  }
    -
    5155 
    -
    5156  if(newCapacity != m_Capacity)
    -
    5157  {
    -
    5158  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
    -
    5159  const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
    -
    5160  if(elementsToCopy != 0)
    -
    5161  {
    -
    5162  memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
    -
    5163  }
    -
    5164  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    -
    5165  m_Capacity = newCapacity;
    -
    5166  m_pArray = newArray;
    -
    5167  }
    -
    5168 
    -
    5169  m_Count = newCount;
    -
    5170  }
    -
    5171 
    -
    5172  void clear()
    -
    5173  {
    -
    5174  resize(0);
    -
    5175  }
    -
    5176 
    -
    5177  void shrink_to_fit()
    -
    5178  {
    -
    5179  if(m_Capacity > m_Count)
    -
    5180  {
    -
    5181  T* newArray = VMA_NULL;
    -
    5182  if(m_Count > 0)
    -
    5183  {
    -
    5184  newArray = VmaAllocateArray<T>(m_Allocator.m_pCallbacks, m_Count);
    -
    5185  memcpy(newArray, m_pArray, m_Count * sizeof(T));
    -
    5186  }
    -
    5187  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    -
    5188  m_Capacity = m_Count;
    -
    5189  m_pArray = newArray;
    -
    5190  }
    -
    5191  }
    -
    5192 
    -
    5193  void insert(size_t index, const T& src)
    -
    5194  {
    -
    5195  VMA_HEAVY_ASSERT(index <= m_Count);
    -
    5196  const size_t oldCount = size();
    -
    5197  resize(oldCount + 1);
    -
    5198  if(index < oldCount)
    -
    5199  {
    -
    5200  memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
    -
    5201  }
    -
    5202  m_pArray[index] = src;
    -
    5203  }
    -
    5204 
    -
    5205  void remove(size_t index)
    -
    5206  {
    -
    5207  VMA_HEAVY_ASSERT(index < m_Count);
    -
    5208  const size_t oldCount = size();
    -
    5209  if(index < oldCount - 1)
    -
    5210  {
    -
    5211  memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
    -
    5212  }
    -
    5213  resize(oldCount - 1);
    -
    5214  }
    -
    5215 
    -
    5216  void push_back(const T& src)
    -
    5217  {
    -
    5218  const size_t newIndex = size();
    -
    5219  resize(newIndex + 1);
    -
    5220  m_pArray[newIndex] = src;
    -
    5221  }
    -
    5222 
    -
    5223  void pop_back()
    -
    5224  {
    -
    5225  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5226  resize(size() - 1);
    -
    5227  }
    -
    5228 
    -
    5229  void push_front(const T& src)
    -
    5230  {
    -
    5231  insert(0, src);
    -
    5232  }
    -
    5233 
    -
    5234  void pop_front()
    -
    5235  {
    -
    5236  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5237  remove(0);
    -
    5238  }
    -
    5239 
    -
    5240  typedef T* iterator;
    -
    5241  typedef const T* const_iterator;
    -
    5242 
    -
    5243  iterator begin() { return m_pArray; }
    -
    5244  iterator end() { return m_pArray + m_Count; }
    -
    5245  const_iterator cbegin() const { return m_pArray; }
    -
    5246  const_iterator cend() const { return m_pArray + m_Count; }
    -
    5247  const_iterator begin() const { return cbegin(); }
    -
    5248  const_iterator end() const { return cend(); }
    -
    5249 
    -
    5250 private:
    -
    5251  AllocatorT m_Allocator;
    -
    5252  T* m_pArray;
    -
    5253  size_t m_Count;
    -
    5254  size_t m_Capacity;
    -
    5255 };
    -
    5256 
    -
    5257 template<typename T, typename allocatorT>
    -
    5258 static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
    -
    5259 {
    -
    5260  vec.insert(index, item);
    -
    5261 }
    -
    5262 
    -
    5263 template<typename T, typename allocatorT>
    -
    5264 static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
    -
    5265 {
    -
    5266  vec.remove(index);
    -
    5267 }
    -
    5268 
    -
    5269 #endif // #if VMA_USE_STL_VECTOR
    -
    5270 
    -
    5271 template<typename CmpLess, typename VectorT>
    -
    5272 size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value)
    -
    5273 {
    -
    5274  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    -
    5275  vector.data(),
    -
    5276  vector.data() + vector.size(),
    -
    5277  value,
    -
    5278  CmpLess()) - vector.data();
    -
    5279  VmaVectorInsert(vector, indexToInsert, value);
    -
    5280  return indexToInsert;
    -
    5281 }
    -
    5282 
    -
    5283 template<typename CmpLess, typename VectorT>
    -
    5284 bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value)
    -
    5285 {
    -
    5286  CmpLess comparator;
    -
    5287  typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
    -
    5288  vector.begin(),
    -
    5289  vector.end(),
    -
    5290  value,
    -
    5291  comparator);
    -
    5292  if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it))
    -
    5293  {
    -
    5294  size_t indexToRemove = it - vector.begin();
    -
    5295  VmaVectorRemove(vector, indexToRemove);
    -
    5296  return true;
    -
    5297  }
    -
    5298  return false;
    -
    5299 }
    -
    5300 
    -
    5302 // class VmaSmallVector
    -
    5303 
    -
    5304 /*
    -
    5305 This is a vector (a variable-sized array), optimized for the case when the array is small.
    -
    5306 
    -
    5307 It contains some number of elements in-place, which allows it to avoid heap allocation
    -
    5308 when the actual number of elements is below that threshold. This allows normal "small"
    -
    5309 cases to be fast without losing generality for large inputs.
    -
    5310 */
    -
    5311 
    -
    5312 template<typename T, typename AllocatorT, size_t N>
    -
    5313 class VmaSmallVector
    -
    5314 {
    -
    5315 public:
    -
    5316  typedef T value_type;
    -
    5317 
    -
    5318  VmaSmallVector(const AllocatorT& allocator) :
    -
    5319  m_Count(0),
    -
    5320  m_DynamicArray(allocator)
    -
    5321  {
    -
    5322  }
    -
    5323  VmaSmallVector(size_t count, const AllocatorT& allocator) :
    -
    5324  m_Count(count),
    -
    5325  m_DynamicArray(count > N ? count : 0, allocator)
    -
    5326  {
    -
    5327  }
    -
    5328  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
    -
    5329  VmaSmallVector(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& src) = delete;
    -
    5330  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
    -
    5331  VmaSmallVector<T, AllocatorT, N>& operator=(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& rhs) = delete;
    +
    5125  const T& front() const
    +
    5126  {
    +
    5127  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5128  return m_pArray[0];
    +
    5129  }
    +
    5130  T& back()
    +
    5131  {
    +
    5132  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5133  return m_pArray[m_Count - 1];
    +
    5134  }
    +
    5135  const T& back() const
    +
    5136  {
    +
    5137  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5138  return m_pArray[m_Count - 1];
    +
    5139  }
    +
    5140 
    +
    5141  void reserve(size_t newCapacity, bool freeMemory = false)
    +
    5142  {
    +
    5143  newCapacity = VMA_MAX(newCapacity, m_Count);
    +
    5144 
    +
    5145  if((newCapacity < m_Capacity) && !freeMemory)
    +
    5146  {
    +
    5147  newCapacity = m_Capacity;
    +
    5148  }
    +
    5149 
    +
    5150  if(newCapacity != m_Capacity)
    +
    5151  {
    +
    5152  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
    +
    5153  if(m_Count != 0)
    +
    5154  {
    +
    5155  memcpy(newArray, m_pArray, m_Count * sizeof(T));
    +
    5156  }
    +
    5157  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    +
    5158  m_Capacity = newCapacity;
    +
    5159  m_pArray = newArray;
    +
    5160  }
    +
    5161  }
    +
    5162 
    +
    5163  void resize(size_t newCount)
    +
    5164  {
    +
    5165  size_t newCapacity = m_Capacity;
    +
    5166  if(newCount > m_Capacity)
    +
    5167  {
    +
    5168  newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
    +
    5169  }
    +
    5170 
    +
    5171  if(newCapacity != m_Capacity)
    +
    5172  {
    +
    5173  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
    +
    5174  const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
    +
    5175  if(elementsToCopy != 0)
    +
    5176  {
    +
    5177  memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
    +
    5178  }
    +
    5179  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    +
    5180  m_Capacity = newCapacity;
    +
    5181  m_pArray = newArray;
    +
    5182  }
    +
    5183 
    +
    5184  m_Count = newCount;
    +
    5185  }
    +
    5186 
    +
    5187  void clear()
    +
    5188  {
    +
    5189  resize(0);
    +
    5190  }
    +
    5191 
    +
    5192  void shrink_to_fit()
    +
    5193  {
    +
    5194  if(m_Capacity > m_Count)
    +
    5195  {
    +
    5196  T* newArray = VMA_NULL;
    +
    5197  if(m_Count > 0)
    +
    5198  {
    +
    5199  newArray = VmaAllocateArray<T>(m_Allocator.m_pCallbacks, m_Count);
    +
    5200  memcpy(newArray, m_pArray, m_Count * sizeof(T));
    +
    5201  }
    +
    5202  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    +
    5203  m_Capacity = m_Count;
    +
    5204  m_pArray = newArray;
    +
    5205  }
    +
    5206  }
    +
    5207 
    +
    5208  void insert(size_t index, const T& src)
    +
    5209  {
    +
    5210  VMA_HEAVY_ASSERT(index <= m_Count);
    +
    5211  const size_t oldCount = size();
    +
    5212  resize(oldCount + 1);
    +
    5213  if(index < oldCount)
    +
    5214  {
    +
    5215  memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
    +
    5216  }
    +
    5217  m_pArray[index] = src;
    +
    5218  }
    +
    5219 
    +
    5220  void remove(size_t index)
    +
    5221  {
    +
    5222  VMA_HEAVY_ASSERT(index < m_Count);
    +
    5223  const size_t oldCount = size();
    +
    5224  if(index < oldCount - 1)
    +
    5225  {
    +
    5226  memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
    +
    5227  }
    +
    5228  resize(oldCount - 1);
    +
    5229  }
    +
    5230 
    +
    5231  void push_back(const T& src)
    +
    5232  {
    +
    5233  const size_t newIndex = size();
    +
    5234  resize(newIndex + 1);
    +
    5235  m_pArray[newIndex] = src;
    +
    5236  }
    +
    5237 
    +
    5238  void pop_back()
    +
    5239  {
    +
    5240  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5241  resize(size() - 1);
    +
    5242  }
    +
    5243 
    +
    5244  void push_front(const T& src)
    +
    5245  {
    +
    5246  insert(0, src);
    +
    5247  }
    +
    5248 
    +
    5249  void pop_front()
    +
    5250  {
    +
    5251  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5252  remove(0);
    +
    5253  }
    +
    5254 
    +
    5255  typedef T* iterator;
    +
    5256  typedef const T* const_iterator;
    +
    5257 
    +
    5258  iterator begin() { return m_pArray; }
    +
    5259  iterator end() { return m_pArray + m_Count; }
    +
    5260  const_iterator cbegin() const { return m_pArray; }
    +
    5261  const_iterator cend() const { return m_pArray + m_Count; }
    +
    5262  const_iterator begin() const { return cbegin(); }
    +
    5263  const_iterator end() const { return cend(); }
    +
    5264 
    +
    5265 private:
    +
    5266  AllocatorT m_Allocator;
    +
    5267  T* m_pArray;
    +
    5268  size_t m_Count;
    +
    5269  size_t m_Capacity;
    +
    5270 };
    +
    5271 
    +
    5272 template<typename T, typename allocatorT>
    +
    5273 static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
    +
    5274 {
    +
    5275  vec.insert(index, item);
    +
    5276 }
    +
    5277 
    +
    5278 template<typename T, typename allocatorT>
    +
    5279 static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
    +
    5280 {
    +
    5281  vec.remove(index);
    +
    5282 }
    +
    5283 
    +
    5284 #endif // #if VMA_USE_STL_VECTOR
    +
    5285 
    +
    5286 template<typename CmpLess, typename VectorT>
    +
    5287 size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value)
    +
    5288 {
    +
    5289  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    +
    5290  vector.data(),
    +
    5291  vector.data() + vector.size(),
    +
    5292  value,
    +
    5293  CmpLess()) - vector.data();
    +
    5294  VmaVectorInsert(vector, indexToInsert, value);
    +
    5295  return indexToInsert;
    +
    5296 }
    +
    5297 
    +
    5298 template<typename CmpLess, typename VectorT>
    +
    5299 bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value)
    +
    5300 {
    +
    5301  CmpLess comparator;
    +
    5302  typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
    +
    5303  vector.begin(),
    +
    5304  vector.end(),
    +
    5305  value,
    +
    5306  comparator);
    +
    5307  if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it))
    +
    5308  {
    +
    5309  size_t indexToRemove = it - vector.begin();
    +
    5310  VmaVectorRemove(vector, indexToRemove);
    +
    5311  return true;
    +
    5312  }
    +
    5313  return false;
    +
    5314 }
    +
    5315 
    +
    5317 // class VmaSmallVector
    +
    5318 
    +
    5319 /*
    +
    5320 This is a vector (a variable-sized array), optimized for the case when the array is small.
    +
    5321 
    +
    5322 It contains some number of elements in-place, which allows it to avoid heap allocation
    +
    5323 when the actual number of elements is below that threshold. This allows normal "small"
    +
    5324 cases to be fast without losing generality for large inputs.
    +
    5325 */
    +
    5326 
    +
    5327 template<typename T, typename AllocatorT, size_t N>
    +
    5328 class VmaSmallVector
    +
    5329 {
    +
    5330 public:
    +
    5331  typedef T value_type;
    5332 
    -
    5333  bool empty() const { return m_Count == 0; }
    -
    5334  size_t size() const { return m_Count; }
    -
    5335  T* data() { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
    -
    5336  const T* data() const { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
    -
    5337 
    -
    5338  T& operator[](size_t index)
    -
    5339  {
    -
    5340  VMA_HEAVY_ASSERT(index < m_Count);
    -
    5341  return data()[index];
    +
    5333  VmaSmallVector(const AllocatorT& allocator) :
    +
    5334  m_Count(0),
    +
    5335  m_DynamicArray(allocator)
    +
    5336  {
    +
    5337  }
    +
    5338  VmaSmallVector(size_t count, const AllocatorT& allocator) :
    +
    5339  m_Count(count),
    +
    5340  m_DynamicArray(count > N ? count : 0, allocator)
    +
    5341  {
    5342  }
    -
    5343  const T& operator[](size_t index) const
    -
    5344  {
    -
    5345  VMA_HEAVY_ASSERT(index < m_Count);
    -
    5346  return data()[index];
    -
    5347  }
    -
    5348 
    -
    5349  T& front()
    -
    5350  {
    -
    5351  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5352  return data()[0];
    -
    5353  }
    -
    5354  const T& front() const
    -
    5355  {
    -
    5356  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5357  return data()[0];
    -
    5358  }
    -
    5359  T& back()
    -
    5360  {
    -
    5361  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5362  return data()[m_Count - 1];
    -
    5363  }
    -
    5364  const T& back() const
    -
    5365  {
    +
    5343  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
    +
    5344  VmaSmallVector(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& src) = delete;
    +
    5345  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
    +
    5346  VmaSmallVector<T, AllocatorT, N>& operator=(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& rhs) = delete;
    +
    5347 
    +
    5348  bool empty() const { return m_Count == 0; }
    +
    5349  size_t size() const { return m_Count; }
    +
    5350  T* data() { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
    +
    5351  const T* data() const { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
    +
    5352 
    +
    5353  T& operator[](size_t index)
    +
    5354  {
    +
    5355  VMA_HEAVY_ASSERT(index < m_Count);
    +
    5356  return data()[index];
    +
    5357  }
    +
    5358  const T& operator[](size_t index) const
    +
    5359  {
    +
    5360  VMA_HEAVY_ASSERT(index < m_Count);
    +
    5361  return data()[index];
    +
    5362  }
    +
    5363 
    +
    5364  T& front()
    +
    5365  {
    5366  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5367  return data()[m_Count - 1];
    +
    5367  return data()[0];
    5368  }
    -
    5369 
    -
    5370  void resize(size_t newCount, bool freeMemory = false)
    -
    5371  {
    -
    5372  if(newCount > N && m_Count > N)
    -
    5373  {
    -
    5374  // Any direction, staying in m_DynamicArray
    -
    5375  m_DynamicArray.resize(newCount);
    -
    5376  if(freeMemory)
    -
    5377  {
    -
    5378  m_DynamicArray.shrink_to_fit();
    -
    5379  }
    -
    5380  }
    -
    5381  else if(newCount > N && m_Count <= N)
    -
    5382  {
    -
    5383  // Growing, moving from m_StaticArray to m_DynamicArray
    -
    5384  m_DynamicArray.resize(newCount);
    -
    5385  if(m_Count > 0)
    -
    5386  {
    -
    5387  memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T));
    -
    5388  }
    -
    5389  }
    -
    5390  else if(newCount <= N && m_Count > N)
    -
    5391  {
    -
    5392  // Shrinking, moving from m_DynamicArray to m_StaticArray
    -
    5393  if(newCount > 0)
    -
    5394  {
    -
    5395  memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T));
    -
    5396  }
    -
    5397  m_DynamicArray.resize(0);
    -
    5398  if(freeMemory)
    -
    5399  {
    -
    5400  m_DynamicArray.shrink_to_fit();
    -
    5401  }
    -
    5402  }
    -
    5403  else
    -
    5404  {
    -
    5405  // Any direction, staying in m_StaticArray - nothing to do here
    -
    5406  }
    -
    5407  m_Count = newCount;
    -
    5408  }
    -
    5409 
    -
    5410  void clear(bool freeMemory = false)
    -
    5411  {
    -
    5412  m_DynamicArray.clear();
    -
    5413  if(freeMemory)
    -
    5414  {
    -
    5415  m_DynamicArray.shrink_to_fit();
    -
    5416  }
    -
    5417  m_Count = 0;
    -
    5418  }
    -
    5419 
    -
    5420  void insert(size_t index, const T& src)
    -
    5421  {
    -
    5422  VMA_HEAVY_ASSERT(index <= m_Count);
    -
    5423  const size_t oldCount = size();
    -
    5424  resize(oldCount + 1);
    -
    5425  T* const dataPtr = data();
    -
    5426  if(index < oldCount)
    -
    5427  {
    -
    5428  // I know, this could be more optimal for case where memmove can be memcpy directly from m_StaticArray to m_DynamicArray.
    -
    5429  memmove(dataPtr + (index + 1), dataPtr + index, (oldCount - index) * sizeof(T));
    -
    5430  }
    -
    5431  dataPtr[index] = src;
    -
    5432  }
    -
    5433 
    -
    5434  void remove(size_t index)
    -
    5435  {
    -
    5436  VMA_HEAVY_ASSERT(index < m_Count);
    -
    5437  const size_t oldCount = size();
    -
    5438  if(index < oldCount - 1)
    -
    5439  {
    -
    5440  // I know, this could be more optimal for case where memmove can be memcpy directly from m_DynamicArray to m_StaticArray.
    -
    5441  T* const dataPtr = data();
    -
    5442  memmove(dataPtr + index, dataPtr + (index + 1), (oldCount - index - 1) * sizeof(T));
    -
    5443  }
    -
    5444  resize(oldCount - 1);
    -
    5445  }
    -
    5446 
    -
    5447  void push_back(const T& src)
    -
    5448  {
    -
    5449  const size_t newIndex = size();
    -
    5450  resize(newIndex + 1);
    -
    5451  data()[newIndex] = src;
    -
    5452  }
    -
    5453 
    -
    5454  void pop_back()
    -
    5455  {
    -
    5456  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5457  resize(size() - 1);
    -
    5458  }
    -
    5459 
    -
    5460  void push_front(const T& src)
    -
    5461  {
    -
    5462  insert(0, src);
    -
    5463  }
    -
    5464 
    -
    5465  void pop_front()
    -
    5466  {
    -
    5467  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5468  remove(0);
    -
    5469  }
    -
    5470 
    -
    5471  typedef T* iterator;
    -
    5472 
    -
    5473  iterator begin() { return data(); }
    -
    5474  iterator end() { return data() + m_Count; }
    -
    5475 
    -
    5476 private:
    -
    5477  size_t m_Count;
    -
    5478  T m_StaticArray[N]; // Used when m_Size <= N
    -
    5479  VmaVector<T, AllocatorT> m_DynamicArray; // Used when m_Size > N
    -
    5480 };
    -
    5481 
    -
    5483 // class VmaPoolAllocator
    -
    5484 
    -
    5485 /*
    -
    5486 Allocator for objects of type T using a list of arrays (pools) to speed up
    -
    5487 allocation. Number of elements that can be allocated is not bounded because
    -
    5488 allocator can create multiple blocks.
    -
    5489 */
    -
    5490 template<typename T>
    -
    5491 class VmaPoolAllocator
    -
    5492 {
    -
    5493  VMA_CLASS_NO_COPY(VmaPoolAllocator)
    -
    5494 public:
    -
    5495  VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity);
    -
    5496  ~VmaPoolAllocator();
    -
    5497  template<typename... Types> T* Alloc(Types... args);
    -
    5498  void Free(T* ptr);
    +
    5369  const T& front() const
    +
    5370  {
    +
    5371  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5372  return data()[0];
    +
    5373  }
    +
    5374  T& back()
    +
    5375  {
    +
    5376  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5377  return data()[m_Count - 1];
    +
    5378  }
    +
    5379  const T& back() const
    +
    5380  {
    +
    5381  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5382  return data()[m_Count - 1];
    +
    5383  }
    +
    5384 
    +
    5385  void resize(size_t newCount, bool freeMemory = false)
    +
    5386  {
    +
    5387  if(newCount > N && m_Count > N)
    +
    5388  {
    +
    5389  // Any direction, staying in m_DynamicArray
    +
    5390  m_DynamicArray.resize(newCount);
    +
    5391  if(freeMemory)
    +
    5392  {
    +
    5393  m_DynamicArray.shrink_to_fit();
    +
    5394  }
    +
    5395  }
    +
    5396  else if(newCount > N && m_Count <= N)
    +
    5397  {
    +
    5398  // Growing, moving from m_StaticArray to m_DynamicArray
    +
    5399  m_DynamicArray.resize(newCount);
    +
    5400  if(m_Count > 0)
    +
    5401  {
    +
    5402  memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T));
    +
    5403  }
    +
    5404  }
    +
    5405  else if(newCount <= N && m_Count > N)
    +
    5406  {
    +
    5407  // Shrinking, moving from m_DynamicArray to m_StaticArray
    +
    5408  if(newCount > 0)
    +
    5409  {
    +
    5410  memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T));
    +
    5411  }
    +
    5412  m_DynamicArray.resize(0);
    +
    5413  if(freeMemory)
    +
    5414  {
    +
    5415  m_DynamicArray.shrink_to_fit();
    +
    5416  }
    +
    5417  }
    +
    5418  else
    +
    5419  {
    +
    5420  // Any direction, staying in m_StaticArray - nothing to do here
    +
    5421  }
    +
    5422  m_Count = newCount;
    +
    5423  }
    +
    5424 
    +
    5425  void clear(bool freeMemory = false)
    +
    5426  {
    +
    5427  m_DynamicArray.clear();
    +
    5428  if(freeMemory)
    +
    5429  {
    +
    5430  m_DynamicArray.shrink_to_fit();
    +
    5431  }
    +
    5432  m_Count = 0;
    +
    5433  }
    +
    5434 
    +
    5435  void insert(size_t index, const T& src)
    +
    5436  {
    +
    5437  VMA_HEAVY_ASSERT(index <= m_Count);
    +
    5438  const size_t oldCount = size();
    +
    5439  resize(oldCount + 1);
    +
    5440  T* const dataPtr = data();
    +
    5441  if(index < oldCount)
    +
    5442  {
    +
    5443  // I know, this could be more optimal for case where memmove can be memcpy directly from m_StaticArray to m_DynamicArray.
    +
    5444  memmove(dataPtr + (index + 1), dataPtr + index, (oldCount - index) * sizeof(T));
    +
    5445  }
    +
    5446  dataPtr[index] = src;
    +
    5447  }
    +
    5448 
    +
    5449  void remove(size_t index)
    +
    5450  {
    +
    5451  VMA_HEAVY_ASSERT(index < m_Count);
    +
    5452  const size_t oldCount = size();
    +
    5453  if(index < oldCount - 1)
    +
    5454  {
    +
    5455  // I know, this could be more optimal for case where memmove can be memcpy directly from m_DynamicArray to m_StaticArray.
    +
    5456  T* const dataPtr = data();
    +
    5457  memmove(dataPtr + index, dataPtr + (index + 1), (oldCount - index - 1) * sizeof(T));
    +
    5458  }
    +
    5459  resize(oldCount - 1);
    +
    5460  }
    +
    5461 
    +
    5462  void push_back(const T& src)
    +
    5463  {
    +
    5464  const size_t newIndex = size();
    +
    5465  resize(newIndex + 1);
    +
    5466  data()[newIndex] = src;
    +
    5467  }
    +
    5468 
    +
    5469  void pop_back()
    +
    5470  {
    +
    5471  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5472  resize(size() - 1);
    +
    5473  }
    +
    5474 
    +
    5475  void push_front(const T& src)
    +
    5476  {
    +
    5477  insert(0, src);
    +
    5478  }
    +
    5479 
    +
    5480  void pop_front()
    +
    5481  {
    +
    5482  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5483  remove(0);
    +
    5484  }
    +
    5485 
    +
    5486  typedef T* iterator;
    +
    5487 
    +
    5488  iterator begin() { return data(); }
    +
    5489  iterator end() { return data() + m_Count; }
    +
    5490 
    +
    5491 private:
    +
    5492  size_t m_Count;
    +
    5493  T m_StaticArray[N]; // Used when m_Size <= N
    +
    5494  VmaVector<T, AllocatorT> m_DynamicArray; // Used when m_Size > N
    +
    5495 };
    +
    5496 
    +
    5498 // class VmaPoolAllocator
    5499 
    -
    5500 private:
    -
    5501  union Item
    -
    5502  {
    -
    5503  uint32_t NextFreeIndex;
    -
    5504  alignas(T) char Value[sizeof(T)];
    -
    5505  };
    -
    5506 
    -
    5507  struct ItemBlock
    -
    5508  {
    -
    5509  Item* pItems;
    -
    5510  uint32_t Capacity;
    -
    5511  uint32_t FirstFreeIndex;
    -
    5512  };
    -
    5513 
    -
    5514  const VkAllocationCallbacks* m_pAllocationCallbacks;
    -
    5515  const uint32_t m_FirstBlockCapacity;
    -
    5516  VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
    -
    5517 
    -
    5518  ItemBlock& CreateNewBlock();
    -
    5519 };
    -
    5520 
    -
    5521 template<typename T>
    -
    5522 VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) :
    -
    5523  m_pAllocationCallbacks(pAllocationCallbacks),
    -
    5524  m_FirstBlockCapacity(firstBlockCapacity),
    -
    5525  m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
    -
    5526 {
    -
    5527  VMA_ASSERT(m_FirstBlockCapacity > 1);
    -
    5528 }
    -
    5529 
    -
    5530 template<typename T>
    -
    5531 VmaPoolAllocator<T>::~VmaPoolAllocator()
    -
    5532 {
    -
    5533  for(size_t i = m_ItemBlocks.size(); i--; )
    -
    5534  vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity);
    -
    5535  m_ItemBlocks.clear();
    -
    5536 }
    -
    5537 
    -
    5538 template<typename T>
    -
    5539 template<typename... Types> T* VmaPoolAllocator<T>::Alloc(Types... args)
    -
    5540 {
    -
    5541  for(size_t i = m_ItemBlocks.size(); i--; )
    -
    5542  {
    -
    5543  ItemBlock& block = m_ItemBlocks[i];
    -
    5544  // This block has some free items: Use first one.
    -
    5545  if(block.FirstFreeIndex != UINT32_MAX)
    -
    5546  {
    -
    5547  Item* const pItem = &block.pItems[block.FirstFreeIndex];
    -
    5548  block.FirstFreeIndex = pItem->NextFreeIndex;
    -
    5549  T* result = (T*)&pItem->Value;
    -
    5550  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
    -
    5551  return result;
    -
    5552  }
    -
    5553  }
    -
    5554 
    -
    5555  // No block has free item: Create new one and use it.
    -
    5556  ItemBlock& newBlock = CreateNewBlock();
    -
    5557  Item* const pItem = &newBlock.pItems[0];
    -
    5558  newBlock.FirstFreeIndex = pItem->NextFreeIndex;
    -
    5559  T* result = (T*)&pItem->Value;
    -
    5560  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
    -
    5561  return result;
    -
    5562 }
    -
    5563 
    -
    5564 template<typename T>
    -
    5565 void VmaPoolAllocator<T>::Free(T* ptr)
    -
    5566 {
    -
    5567  // Search all memory blocks to find ptr.
    -
    5568  for(size_t i = m_ItemBlocks.size(); i--; )
    -
    5569  {
    -
    5570  ItemBlock& block = m_ItemBlocks[i];
    -
    5571 
    -
    5572  // Casting to union.
    -
    5573  Item* pItemPtr;
    -
    5574  memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
    -
    5575 
    -
    5576  // Check if pItemPtr is in address range of this block.
    -
    5577  if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity))
    -
    5578  {
    -
    5579  ptr->~T(); // Explicit destructor call.
    -
    5580  const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
    -
    5581  pItemPtr->NextFreeIndex = block.FirstFreeIndex;
    -
    5582  block.FirstFreeIndex = index;
    -
    5583  return;
    -
    5584  }
    -
    5585  }
    -
    5586  VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
    -
    5587 }
    -
    5588 
    -
    5589 template<typename T>
    -
    5590 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
    -
    5591 {
    -
    5592  const uint32_t newBlockCapacity = m_ItemBlocks.empty() ?
    -
    5593  m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2;
    -
    5594 
    -
    5595  const ItemBlock newBlock = {
    -
    5596  vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity),
    -
    5597  newBlockCapacity,
    -
    5598  0 };
    -
    5599 
    -
    5600  m_ItemBlocks.push_back(newBlock);
    -
    5601 
    -
    5602  // Setup singly-linked list of all free items in this block.
    -
    5603  for(uint32_t i = 0; i < newBlockCapacity - 1; ++i)
    -
    5604  newBlock.pItems[i].NextFreeIndex = i + 1;
    -
    5605  newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
    -
    5606  return m_ItemBlocks.back();
    -
    5607 }
    -
    5608 
    -
    5610 // class VmaRawList, VmaList
    -
    5611 
    -
    5612 #if VMA_USE_STL_LIST
    -
    5613 
    -
    5614 #define VmaList std::list
    -
    5615 
    -
    5616 #else // #if VMA_USE_STL_LIST
    -
    5617 
    -
    5618 template<typename T>
    -
    5619 struct VmaListItem
    -
    5620 {
    -
    5621  VmaListItem* pPrev;
    -
    5622  VmaListItem* pNext;
    -
    5623  T Value;
    -
    5624 };
    -
    5625 
    -
    5626 // Doubly linked list.
    -
    5627 template<typename T>
    -
    5628 class VmaRawList
    -
    5629 {
    -
    5630  VMA_CLASS_NO_COPY(VmaRawList)
    -
    5631 public:
    -
    5632  typedef VmaListItem<T> ItemType;
    -
    5633 
    -
    5634  VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
    -
    5635  ~VmaRawList();
    -
    5636  void Clear();
    -
    5637 
    -
    5638  size_t GetCount() const { return m_Count; }
    -
    5639  bool IsEmpty() const { return m_Count == 0; }
    +
    5500 /*
    +
    5501 Allocator for objects of type T using a list of arrays (pools) to speed up
    +
    5502 allocation. Number of elements that can be allocated is not bounded because
    +
    5503 allocator can create multiple blocks.
    +
    5504 */
    +
    5505 template<typename T>
    +
    5506 class VmaPoolAllocator
    +
    5507 {
    +
    5508  VMA_CLASS_NO_COPY(VmaPoolAllocator)
    +
    5509 public:
    +
    5510  VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity);
    +
    5511  ~VmaPoolAllocator();
    +
    5512  template<typename... Types> T* Alloc(Types... args);
    +
    5513  void Free(T* ptr);
    +
    5514 
    +
    5515 private:
    +
    5516  union Item
    +
    5517  {
    +
    5518  uint32_t NextFreeIndex;
    +
    5519  alignas(T) char Value[sizeof(T)];
    +
    5520  };
    +
    5521 
    +
    5522  struct ItemBlock
    +
    5523  {
    +
    5524  Item* pItems;
    +
    5525  uint32_t Capacity;
    +
    5526  uint32_t FirstFreeIndex;
    +
    5527  };
    +
    5528 
    +
    5529  const VkAllocationCallbacks* m_pAllocationCallbacks;
    +
    5530  const uint32_t m_FirstBlockCapacity;
    +
    5531  VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
    +
    5532 
    +
    5533  ItemBlock& CreateNewBlock();
    +
    5534 };
    +
    5535 
    +
    5536 template<typename T>
    +
    5537 VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) :
    +
    5538  m_pAllocationCallbacks(pAllocationCallbacks),
    +
    5539  m_FirstBlockCapacity(firstBlockCapacity),
    +
    5540  m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
    +
    5541 {
    +
    5542  VMA_ASSERT(m_FirstBlockCapacity > 1);
    +
    5543 }
    +
    5544 
    +
    5545 template<typename T>
    +
    5546 VmaPoolAllocator<T>::~VmaPoolAllocator()
    +
    5547 {
    +
    5548  for(size_t i = m_ItemBlocks.size(); i--; )
    +
    5549  vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity);
    +
    5550  m_ItemBlocks.clear();
    +
    5551 }
    +
    5552 
    +
    5553 template<typename T>
    +
    5554 template<typename... Types> T* VmaPoolAllocator<T>::Alloc(Types... args)
    +
    5555 {
    +
    5556  for(size_t i = m_ItemBlocks.size(); i--; )
    +
    5557  {
    +
    5558  ItemBlock& block = m_ItemBlocks[i];
    +
    5559  // This block has some free items: Use first one.
    +
    5560  if(block.FirstFreeIndex != UINT32_MAX)
    +
    5561  {
    +
    5562  Item* const pItem = &block.pItems[block.FirstFreeIndex];
    +
    5563  block.FirstFreeIndex = pItem->NextFreeIndex;
    +
    5564  T* result = (T*)&pItem->Value;
    +
    5565  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
    +
    5566  return result;
    +
    5567  }
    +
    5568  }
    +
    5569 
    +
    5570  // No block has free item: Create new one and use it.
    +
    5571  ItemBlock& newBlock = CreateNewBlock();
    +
    5572  Item* const pItem = &newBlock.pItems[0];
    +
    5573  newBlock.FirstFreeIndex = pItem->NextFreeIndex;
    +
    5574  T* result = (T*)&pItem->Value;
    +
    5575  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
    +
    5576  return result;
    +
    5577 }
    +
    5578 
    +
    5579 template<typename T>
    +
    5580 void VmaPoolAllocator<T>::Free(T* ptr)
    +
    5581 {
    +
    5582  // Search all memory blocks to find ptr.
    +
    5583  for(size_t i = m_ItemBlocks.size(); i--; )
    +
    5584  {
    +
    5585  ItemBlock& block = m_ItemBlocks[i];
    +
    5586 
    +
    5587  // Casting to union.
    +
    5588  Item* pItemPtr;
    +
    5589  memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
    +
    5590 
    +
    5591  // Check if pItemPtr is in address range of this block.
    +
    5592  if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity))
    +
    5593  {
    +
    5594  ptr->~T(); // Explicit destructor call.
    +
    5595  const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
    +
    5596  pItemPtr->NextFreeIndex = block.FirstFreeIndex;
    +
    5597  block.FirstFreeIndex = index;
    +
    5598  return;
    +
    5599  }
    +
    5600  }
    +
    5601  VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
    +
    5602 }
    +
    5603 
    +
    5604 template<typename T>
    +
    5605 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
    +
    5606 {
    +
    5607  const uint32_t newBlockCapacity = m_ItemBlocks.empty() ?
    +
    5608  m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2;
    +
    5609 
    +
    5610  const ItemBlock newBlock = {
    +
    5611  vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity),
    +
    5612  newBlockCapacity,
    +
    5613  0 };
    +
    5614 
    +
    5615  m_ItemBlocks.push_back(newBlock);
    +
    5616 
    +
    5617  // Setup singly-linked list of all free items in this block.
    +
    5618  for(uint32_t i = 0; i < newBlockCapacity - 1; ++i)
    +
    5619  newBlock.pItems[i].NextFreeIndex = i + 1;
    +
    5620  newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
    +
    5621  return m_ItemBlocks.back();
    +
    5622 }
    +
    5623 
    +
    5625 // class VmaRawList, VmaList
    +
    5626 
    +
    5627 #if VMA_USE_STL_LIST
    +
    5628 
    +
    5629 #define VmaList std::list
    +
    5630 
    +
    5631 #else // #if VMA_USE_STL_LIST
    +
    5632 
    +
    5633 template<typename T>
    +
    5634 struct VmaListItem
    +
    5635 {
    +
    5636  VmaListItem* pPrev;
    +
    5637  VmaListItem* pNext;
    +
    5638  T Value;
    +
    5639 };
    5640 
    -
    5641  ItemType* Front() { return m_pFront; }
    -
    5642  const ItemType* Front() const { return m_pFront; }
    -
    5643  ItemType* Back() { return m_pBack; }
    -
    5644  const ItemType* Back() const { return m_pBack; }
    -
    5645 
    -
    5646  ItemType* PushBack();
    -
    5647  ItemType* PushFront();
    -
    5648  ItemType* PushBack(const T& value);
    -
    5649  ItemType* PushFront(const T& value);
    -
    5650  void PopBack();
    -
    5651  void PopFront();
    +
    5641 // Doubly linked list.
    +
    5642 template<typename T>
    +
    5643 class VmaRawList
    +
    5644 {
    +
    5645  VMA_CLASS_NO_COPY(VmaRawList)
    +
    5646 public:
    +
    5647  typedef VmaListItem<T> ItemType;
    +
    5648 
    +
    5649  VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
    +
    5650  ~VmaRawList();
    +
    5651  void Clear();
    5652 
    -
    5653  // Item can be null - it means PushBack.
    -
    5654  ItemType* InsertBefore(ItemType* pItem);
    -
    5655  // Item can be null - it means PushFront.
    -
    5656  ItemType* InsertAfter(ItemType* pItem);
    -
    5657 
    -
    5658  ItemType* InsertBefore(ItemType* pItem, const T& value);
    -
    5659  ItemType* InsertAfter(ItemType* pItem, const T& value);
    +
    5653  size_t GetCount() const { return m_Count; }
    +
    5654  bool IsEmpty() const { return m_Count == 0; }
    +
    5655 
    +
    5656  ItemType* Front() { return m_pFront; }
    +
    5657  const ItemType* Front() const { return m_pFront; }
    +
    5658  ItemType* Back() { return m_pBack; }
    +
    5659  const ItemType* Back() const { return m_pBack; }
    5660 
    -
    5661  void Remove(ItemType* pItem);
    -
    5662 
    -
    5663 private:
    -
    5664  const VkAllocationCallbacks* const m_pAllocationCallbacks;
    -
    5665  VmaPoolAllocator<ItemType> m_ItemAllocator;
    -
    5666  ItemType* m_pFront;
    -
    5667  ItemType* m_pBack;
    -
    5668  size_t m_Count;
    -
    5669 };
    -
    5670 
    -
    5671 template<typename T>
    -
    5672 VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
    -
    5673  m_pAllocationCallbacks(pAllocationCallbacks),
    -
    5674  m_ItemAllocator(pAllocationCallbacks, 128),
    -
    5675  m_pFront(VMA_NULL),
    -
    5676  m_pBack(VMA_NULL),
    -
    5677  m_Count(0)
    -
    5678 {
    -
    5679 }
    -
    5680 
    -
    5681 template<typename T>
    -
    5682 VmaRawList<T>::~VmaRawList()
    -
    5683 {
    -
    5684  // Intentionally not calling Clear, because that would be unnecessary
    -
    5685  // computations to return all items to m_ItemAllocator as free.
    -
    5686 }
    -
    5687 
    -
    5688 template<typename T>
    -
    5689 void VmaRawList<T>::Clear()
    -
    5690 {
    -
    5691  if(IsEmpty() == false)
    -
    5692  {
    -
    5693  ItemType* pItem = m_pBack;
    -
    5694  while(pItem != VMA_NULL)
    -
    5695  {
    -
    5696  ItemType* const pPrevItem = pItem->pPrev;
    -
    5697  m_ItemAllocator.Free(pItem);
    -
    5698  pItem = pPrevItem;
    -
    5699  }
    -
    5700  m_pFront = VMA_NULL;
    -
    5701  m_pBack = VMA_NULL;
    -
    5702  m_Count = 0;
    -
    5703  }
    -
    5704 }
    -
    5705 
    -
    5706 template<typename T>
    -
    5707 VmaListItem<T>* VmaRawList<T>::PushBack()
    -
    5708 {
    -
    5709  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    -
    5710  pNewItem->pNext = VMA_NULL;
    -
    5711  if(IsEmpty())
    -
    5712  {
    -
    5713  pNewItem->pPrev = VMA_NULL;
    -
    5714  m_pFront = pNewItem;
    -
    5715  m_pBack = pNewItem;
    -
    5716  m_Count = 1;
    -
    5717  }
    -
    5718  else
    -
    5719  {
    -
    5720  pNewItem->pPrev = m_pBack;
    -
    5721  m_pBack->pNext = pNewItem;
    -
    5722  m_pBack = pNewItem;
    -
    5723  ++m_Count;
    -
    5724  }
    -
    5725  return pNewItem;
    -
    5726 }
    -
    5727 
    -
    5728 template<typename T>
    -
    5729 VmaListItem<T>* VmaRawList<T>::PushFront()
    -
    5730 {
    -
    5731  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    -
    5732  pNewItem->pPrev = VMA_NULL;
    -
    5733  if(IsEmpty())
    +
    5661  ItemType* PushBack();
    +
    5662  ItemType* PushFront();
    +
    5663  ItemType* PushBack(const T& value);
    +
    5664  ItemType* PushFront(const T& value);
    +
    5665  void PopBack();
    +
    5666  void PopFront();
    +
    5667 
    +
    5668  // Item can be null - it means PushBack.
    +
    5669  ItemType* InsertBefore(ItemType* pItem);
    +
    5670  // Item can be null - it means PushFront.
    +
    5671  ItemType* InsertAfter(ItemType* pItem);
    +
    5672 
    +
    5673  ItemType* InsertBefore(ItemType* pItem, const T& value);
    +
    5674  ItemType* InsertAfter(ItemType* pItem, const T& value);
    +
    5675 
    +
    5676  void Remove(ItemType* pItem);
    +
    5677 
    +
    5678 private:
    +
    5679  const VkAllocationCallbacks* const m_pAllocationCallbacks;
    +
    5680  VmaPoolAllocator<ItemType> m_ItemAllocator;
    +
    5681  ItemType* m_pFront;
    +
    5682  ItemType* m_pBack;
    +
    5683  size_t m_Count;
    +
    5684 };
    +
    5685 
    +
    5686 template<typename T>
    +
    5687 VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
    +
    5688  m_pAllocationCallbacks(pAllocationCallbacks),
    +
    5689  m_ItemAllocator(pAllocationCallbacks, 128),
    +
    5690  m_pFront(VMA_NULL),
    +
    5691  m_pBack(VMA_NULL),
    +
    5692  m_Count(0)
    +
    5693 {
    +
    5694 }
    +
    5695 
    +
    5696 template<typename T>
    +
    5697 VmaRawList<T>::~VmaRawList()
    +
    5698 {
    +
    5699  // Intentionally not calling Clear, because that would be unnecessary
    +
    5700  // computations to return all items to m_ItemAllocator as free.
    +
    5701 }
    +
    5702 
    +
    5703 template<typename T>
    +
    5704 void VmaRawList<T>::Clear()
    +
    5705 {
    +
    5706  if(IsEmpty() == false)
    +
    5707  {
    +
    5708  ItemType* pItem = m_pBack;
    +
    5709  while(pItem != VMA_NULL)
    +
    5710  {
    +
    5711  ItemType* const pPrevItem = pItem->pPrev;
    +
    5712  m_ItemAllocator.Free(pItem);
    +
    5713  pItem = pPrevItem;
    +
    5714  }
    +
    5715  m_pFront = VMA_NULL;
    +
    5716  m_pBack = VMA_NULL;
    +
    5717  m_Count = 0;
    +
    5718  }
    +
    5719 }
    +
    5720 
    +
    5721 template<typename T>
    +
    5722 VmaListItem<T>* VmaRawList<T>::PushBack()
    +
    5723 {
    +
    5724  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    +
    5725  pNewItem->pNext = VMA_NULL;
    +
    5726  if(IsEmpty())
    +
    5727  {
    +
    5728  pNewItem->pPrev = VMA_NULL;
    +
    5729  m_pFront = pNewItem;
    +
    5730  m_pBack = pNewItem;
    +
    5731  m_Count = 1;
    +
    5732  }
    +
    5733  else
    5734  {
    -
    5735  pNewItem->pNext = VMA_NULL;
    -
    5736  m_pFront = pNewItem;
    +
    5735  pNewItem->pPrev = m_pBack;
    +
    5736  m_pBack->pNext = pNewItem;
    5737  m_pBack = pNewItem;
    -
    5738  m_Count = 1;
    +
    5738  ++m_Count;
    5739  }
    -
    5740  else
    -
    5741  {
    -
    5742  pNewItem->pNext = m_pFront;
    -
    5743  m_pFront->pPrev = pNewItem;
    -
    5744  m_pFront = pNewItem;
    -
    5745  ++m_Count;
    -
    5746  }
    -
    5747  return pNewItem;
    -
    5748 }
    -
    5749 
    -
    5750 template<typename T>
    -
    5751 VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
    -
    5752 {
    -
    5753  ItemType* const pNewItem = PushBack();
    -
    5754  pNewItem->Value = value;
    -
    5755  return pNewItem;
    -
    5756 }
    -
    5757 
    -
    5758 template<typename T>
    -
    5759 VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
    -
    5760 {
    -
    5761  ItemType* const pNewItem = PushFront();
    -
    5762  pNewItem->Value = value;
    -
    5763  return pNewItem;
    -
    5764 }
    -
    5765 
    -
    5766 template<typename T>
    -
    5767 void VmaRawList<T>::PopBack()
    -
    5768 {
    -
    5769  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5770  ItemType* const pBackItem = m_pBack;
    -
    5771  ItemType* const pPrevItem = pBackItem->pPrev;
    -
    5772  if(pPrevItem != VMA_NULL)
    -
    5773  {
    -
    5774  pPrevItem->pNext = VMA_NULL;
    -
    5775  }
    -
    5776  m_pBack = pPrevItem;
    -
    5777  m_ItemAllocator.Free(pBackItem);
    -
    5778  --m_Count;
    +
    5740  return pNewItem;
    +
    5741 }
    +
    5742 
    +
    5743 template<typename T>
    +
    5744 VmaListItem<T>* VmaRawList<T>::PushFront()
    +
    5745 {
    +
    5746  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    +
    5747  pNewItem->pPrev = VMA_NULL;
    +
    5748  if(IsEmpty())
    +
    5749  {
    +
    5750  pNewItem->pNext = VMA_NULL;
    +
    5751  m_pFront = pNewItem;
    +
    5752  m_pBack = pNewItem;
    +
    5753  m_Count = 1;
    +
    5754  }
    +
    5755  else
    +
    5756  {
    +
    5757  pNewItem->pNext = m_pFront;
    +
    5758  m_pFront->pPrev = pNewItem;
    +
    5759  m_pFront = pNewItem;
    +
    5760  ++m_Count;
    +
    5761  }
    +
    5762  return pNewItem;
    +
    5763 }
    +
    5764 
    +
    5765 template<typename T>
    +
    5766 VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
    +
    5767 {
    +
    5768  ItemType* const pNewItem = PushBack();
    +
    5769  pNewItem->Value = value;
    +
    5770  return pNewItem;
    +
    5771 }
    +
    5772 
    +
    5773 template<typename T>
    +
    5774 VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
    +
    5775 {
    +
    5776  ItemType* const pNewItem = PushFront();
    +
    5777  pNewItem->Value = value;
    +
    5778  return pNewItem;
    5779 }
    5780 
    5781 template<typename T>
    -
    5782 void VmaRawList<T>::PopFront()
    +
    5782 void VmaRawList<T>::PopBack()
    5783 {
    5784  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5785  ItemType* const pFrontItem = m_pFront;
    -
    5786  ItemType* const pNextItem = pFrontItem->pNext;
    -
    5787  if(pNextItem != VMA_NULL)
    +
    5785  ItemType* const pBackItem = m_pBack;
    +
    5786  ItemType* const pPrevItem = pBackItem->pPrev;
    +
    5787  if(pPrevItem != VMA_NULL)
    5788  {
    -
    5789  pNextItem->pPrev = VMA_NULL;
    +
    5789  pPrevItem->pNext = VMA_NULL;
    5790  }
    -
    5791  m_pFront = pNextItem;
    -
    5792  m_ItemAllocator.Free(pFrontItem);
    +
    5791  m_pBack = pPrevItem;
    +
    5792  m_ItemAllocator.Free(pBackItem);
    5793  --m_Count;
    5794 }
    5795 
    5796 template<typename T>
    -
    5797 void VmaRawList<T>::Remove(ItemType* pItem)
    +
    5797 void VmaRawList<T>::PopFront()
    5798 {
    -
    5799  VMA_HEAVY_ASSERT(pItem != VMA_NULL);
    -
    5800  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    5801 
    -
    5802  if(pItem->pPrev != VMA_NULL)
    +
    5799  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5800  ItemType* const pFrontItem = m_pFront;
    +
    5801  ItemType* const pNextItem = pFrontItem->pNext;
    +
    5802  if(pNextItem != VMA_NULL)
    5803  {
    -
    5804  pItem->pPrev->pNext = pItem->pNext;
    +
    5804  pNextItem->pPrev = VMA_NULL;
    5805  }
    -
    5806  else
    -
    5807  {
    -
    5808  VMA_HEAVY_ASSERT(m_pFront == pItem);
    -
    5809  m_pFront = pItem->pNext;
    -
    5810  }
    -
    5811 
    -
    5812  if(pItem->pNext != VMA_NULL)
    -
    5813  {
    -
    5814  pItem->pNext->pPrev = pItem->pPrev;
    -
    5815  }
    -
    5816  else
    -
    5817  {
    -
    5818  VMA_HEAVY_ASSERT(m_pBack == pItem);
    -
    5819  m_pBack = pItem->pPrev;
    +
    5806  m_pFront = pNextItem;
    +
    5807  m_ItemAllocator.Free(pFrontItem);
    +
    5808  --m_Count;
    +
    5809 }
    +
    5810 
    +
    5811 template<typename T>
    +
    5812 void VmaRawList<T>::Remove(ItemType* pItem)
    +
    5813 {
    +
    5814  VMA_HEAVY_ASSERT(pItem != VMA_NULL);
    +
    5815  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    5816 
    +
    5817  if(pItem->pPrev != VMA_NULL)
    +
    5818  {
    +
    5819  pItem->pPrev->pNext = pItem->pNext;
    5820  }
    -
    5821 
    -
    5822  m_ItemAllocator.Free(pItem);
    -
    5823  --m_Count;
    -
    5824 }
    -
    5825 
    -
    5826 template<typename T>
    -
    5827 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
    -
    5828 {
    -
    5829  if(pItem != VMA_NULL)
    -
    5830  {
    -
    5831  ItemType* const prevItem = pItem->pPrev;
    -
    5832  ItemType* const newItem = m_ItemAllocator.Alloc();
    -
    5833  newItem->pPrev = prevItem;
    -
    5834  newItem->pNext = pItem;
    -
    5835  pItem->pPrev = newItem;
    -
    5836  if(prevItem != VMA_NULL)
    -
    5837  {
    -
    5838  prevItem->pNext = newItem;
    -
    5839  }
    -
    5840  else
    -
    5841  {
    -
    5842  VMA_HEAVY_ASSERT(m_pFront == pItem);
    -
    5843  m_pFront = newItem;
    -
    5844  }
    -
    5845  ++m_Count;
    -
    5846  return newItem;
    -
    5847  }
    -
    5848  else
    -
    5849  return PushBack();
    -
    5850 }
    -
    5851 
    -
    5852 template<typename T>
    -
    5853 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
    -
    5854 {
    -
    5855  if(pItem != VMA_NULL)
    -
    5856  {
    -
    5857  ItemType* const nextItem = pItem->pNext;
    -
    5858  ItemType* const newItem = m_ItemAllocator.Alloc();
    -
    5859  newItem->pNext = nextItem;
    -
    5860  newItem->pPrev = pItem;
    -
    5861  pItem->pNext = newItem;
    -
    5862  if(nextItem != VMA_NULL)
    -
    5863  {
    -
    5864  nextItem->pPrev = newItem;
    -
    5865  }
    -
    5866  else
    -
    5867  {
    -
    5868  VMA_HEAVY_ASSERT(m_pBack == pItem);
    -
    5869  m_pBack = newItem;
    -
    5870  }
    -
    5871  ++m_Count;
    -
    5872  return newItem;
    -
    5873  }
    -
    5874  else
    -
    5875  return PushFront();
    -
    5876 }
    -
    5877 
    -
    5878 template<typename T>
    -
    5879 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
    -
    5880 {
    -
    5881  ItemType* const newItem = InsertBefore(pItem);
    -
    5882  newItem->Value = value;
    -
    5883  return newItem;
    -
    5884 }
    -
    5885 
    -
    5886 template<typename T>
    -
    5887 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
    -
    5888 {
    -
    5889  ItemType* const newItem = InsertAfter(pItem);
    -
    5890  newItem->Value = value;
    -
    5891  return newItem;
    -
    5892 }
    -
    5893 
    -
    5894 template<typename T, typename AllocatorT>
    -
    5895 class VmaList
    -
    5896 {
    -
    5897  VMA_CLASS_NO_COPY(VmaList)
    -
    5898 public:
    -
    5899  class iterator
    -
    5900  {
    -
    5901  public:
    -
    5902  iterator() :
    -
    5903  m_pList(VMA_NULL),
    -
    5904  m_pItem(VMA_NULL)
    -
    5905  {
    -
    5906  }
    -
    5907 
    -
    5908  T& operator*() const
    -
    5909  {
    -
    5910  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    -
    5911  return m_pItem->Value;
    -
    5912  }
    -
    5913  T* operator->() const
    -
    5914  {
    -
    5915  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    -
    5916  return &m_pItem->Value;
    -
    5917  }
    -
    5918 
    -
    5919  iterator& operator++()
    +
    5821  else
    +
    5822  {
    +
    5823  VMA_HEAVY_ASSERT(m_pFront == pItem);
    +
    5824  m_pFront = pItem->pNext;
    +
    5825  }
    +
    5826 
    +
    5827  if(pItem->pNext != VMA_NULL)
    +
    5828  {
    +
    5829  pItem->pNext->pPrev = pItem->pPrev;
    +
    5830  }
    +
    5831  else
    +
    5832  {
    +
    5833  VMA_HEAVY_ASSERT(m_pBack == pItem);
    +
    5834  m_pBack = pItem->pPrev;
    +
    5835  }
    +
    5836 
    +
    5837  m_ItemAllocator.Free(pItem);
    +
    5838  --m_Count;
    +
    5839 }
    +
    5840 
    +
    5841 template<typename T>
    +
    5842 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
    +
    5843 {
    +
    5844  if(pItem != VMA_NULL)
    +
    5845  {
    +
    5846  ItemType* const prevItem = pItem->pPrev;
    +
    5847  ItemType* const newItem = m_ItemAllocator.Alloc();
    +
    5848  newItem->pPrev = prevItem;
    +
    5849  newItem->pNext = pItem;
    +
    5850  pItem->pPrev = newItem;
    +
    5851  if(prevItem != VMA_NULL)
    +
    5852  {
    +
    5853  prevItem->pNext = newItem;
    +
    5854  }
    +
    5855  else
    +
    5856  {
    +
    5857  VMA_HEAVY_ASSERT(m_pFront == pItem);
    +
    5858  m_pFront = newItem;
    +
    5859  }
    +
    5860  ++m_Count;
    +
    5861  return newItem;
    +
    5862  }
    +
    5863  else
    +
    5864  return PushBack();
    +
    5865 }
    +
    5866 
    +
    5867 template<typename T>
    +
    5868 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
    +
    5869 {
    +
    5870  if(pItem != VMA_NULL)
    +
    5871  {
    +
    5872  ItemType* const nextItem = pItem->pNext;
    +
    5873  ItemType* const newItem = m_ItemAllocator.Alloc();
    +
    5874  newItem->pNext = nextItem;
    +
    5875  newItem->pPrev = pItem;
    +
    5876  pItem->pNext = newItem;
    +
    5877  if(nextItem != VMA_NULL)
    +
    5878  {
    +
    5879  nextItem->pPrev = newItem;
    +
    5880  }
    +
    5881  else
    +
    5882  {
    +
    5883  VMA_HEAVY_ASSERT(m_pBack == pItem);
    +
    5884  m_pBack = newItem;
    +
    5885  }
    +
    5886  ++m_Count;
    +
    5887  return newItem;
    +
    5888  }
    +
    5889  else
    +
    5890  return PushFront();
    +
    5891 }
    +
    5892 
    +
    5893 template<typename T>
    +
    5894 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
    +
    5895 {
    +
    5896  ItemType* const newItem = InsertBefore(pItem);
    +
    5897  newItem->Value = value;
    +
    5898  return newItem;
    +
    5899 }
    +
    5900 
    +
    5901 template<typename T>
    +
    5902 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
    +
    5903 {
    +
    5904  ItemType* const newItem = InsertAfter(pItem);
    +
    5905  newItem->Value = value;
    +
    5906  return newItem;
    +
    5907 }
    +
    5908 
    +
    5909 template<typename T, typename AllocatorT>
    +
    5910 class VmaList
    +
    5911 {
    +
    5912  VMA_CLASS_NO_COPY(VmaList)
    +
    5913 public:
    +
    5914  class iterator
    +
    5915  {
    +
    5916  public:
    +
    5917  iterator() :
    +
    5918  m_pList(VMA_NULL),
    +
    5919  m_pItem(VMA_NULL)
    5920  {
    -
    5921  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    -
    5922  m_pItem = m_pItem->pNext;
    -
    5923  return *this;
    -
    5924  }
    -
    5925  iterator& operator--()
    -
    5926  {
    -
    5927  if(m_pItem != VMA_NULL)
    -
    5928  {
    -
    5929  m_pItem = m_pItem->pPrev;
    -
    5930  }
    -
    5931  else
    -
    5932  {
    -
    5933  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
    -
    5934  m_pItem = m_pList->Back();
    -
    5935  }
    -
    5936  return *this;
    -
    5937  }
    -
    5938 
    -
    5939  iterator operator++(int)
    -
    5940  {
    -
    5941  iterator result = *this;
    -
    5942  ++*this;
    -
    5943  return result;
    -
    5944  }
    -
    5945  iterator operator--(int)
    -
    5946  {
    -
    5947  iterator result = *this;
    -
    5948  --*this;
    -
    5949  return result;
    -
    5950  }
    -
    5951 
    -
    5952  bool operator==(const iterator& rhs) const
    -
    5953  {
    -
    5954  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    -
    5955  return m_pItem == rhs.m_pItem;
    -
    5956  }
    -
    5957  bool operator!=(const iterator& rhs) const
    -
    5958  {
    -
    5959  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    -
    5960  return m_pItem != rhs.m_pItem;
    -
    5961  }
    -
    5962 
    -
    5963  private:
    -
    5964  VmaRawList<T>* m_pList;
    -
    5965  VmaListItem<T>* m_pItem;
    +
    5921  }
    +
    5922 
    +
    5923  T& operator*() const
    +
    5924  {
    +
    5925  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    +
    5926  return m_pItem->Value;
    +
    5927  }
    +
    5928  T* operator->() const
    +
    5929  {
    +
    5930  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    +
    5931  return &m_pItem->Value;
    +
    5932  }
    +
    5933 
    +
    5934  iterator& operator++()
    +
    5935  {
    +
    5936  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    +
    5937  m_pItem = m_pItem->pNext;
    +
    5938  return *this;
    +
    5939  }
    +
    5940  iterator& operator--()
    +
    5941  {
    +
    5942  if(m_pItem != VMA_NULL)
    +
    5943  {
    +
    5944  m_pItem = m_pItem->pPrev;
    +
    5945  }
    +
    5946  else
    +
    5947  {
    +
    5948  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
    +
    5949  m_pItem = m_pList->Back();
    +
    5950  }
    +
    5951  return *this;
    +
    5952  }
    +
    5953 
    +
    5954  iterator operator++(int)
    +
    5955  {
    +
    5956  iterator result = *this;
    +
    5957  ++*this;
    +
    5958  return result;
    +
    5959  }
    +
    5960  iterator operator--(int)
    +
    5961  {
    +
    5962  iterator result = *this;
    +
    5963  --*this;
    +
    5964  return result;
    +
    5965  }
    5966 
    -
    5967  iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
    -
    5968  m_pList(pList),
    -
    5969  m_pItem(pItem)
    -
    5970  {
    +
    5967  bool operator==(const iterator& rhs) const
    +
    5968  {
    +
    5969  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    +
    5970  return m_pItem == rhs.m_pItem;
    5971  }
    -
    5972 
    -
    5973  friend class VmaList<T, AllocatorT>;
    -
    5974  };
    -
    5975 
    -
    5976  class const_iterator
    -
    5977  {
    -
    5978  public:
    -
    5979  const_iterator() :
    -
    5980  m_pList(VMA_NULL),
    -
    5981  m_pItem(VMA_NULL)
    -
    5982  {
    -
    5983  }
    -
    5984 
    -
    5985  const_iterator(const iterator& src) :
    -
    5986  m_pList(src.m_pList),
    -
    5987  m_pItem(src.m_pItem)
    -
    5988  {
    -
    5989  }
    +
    5972  bool operator!=(const iterator& rhs) const
    +
    5973  {
    +
    5974  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    +
    5975  return m_pItem != rhs.m_pItem;
    +
    5976  }
    +
    5977 
    +
    5978  private:
    +
    5979  VmaRawList<T>* m_pList;
    +
    5980  VmaListItem<T>* m_pItem;
    +
    5981 
    +
    5982  iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
    +
    5983  m_pList(pList),
    +
    5984  m_pItem(pItem)
    +
    5985  {
    +
    5986  }
    +
    5987 
    +
    5988  friend class VmaList<T, AllocatorT>;
    +
    5989  };
    5990 
    -
    5991  const T& operator*() const
    -
    5992  {
    -
    5993  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    -
    5994  return m_pItem->Value;
    -
    5995  }
    -
    5996  const T* operator->() const
    -
    5997  {
    -
    5998  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    -
    5999  return &m_pItem->Value;
    -
    6000  }
    -
    6001 
    -
    6002  const_iterator& operator++()
    +
    5991  class const_iterator
    +
    5992  {
    +
    5993  public:
    +
    5994  const_iterator() :
    +
    5995  m_pList(VMA_NULL),
    +
    5996  m_pItem(VMA_NULL)
    +
    5997  {
    +
    5998  }
    +
    5999 
    +
    6000  const_iterator(const iterator& src) :
    +
    6001  m_pList(src.m_pList),
    +
    6002  m_pItem(src.m_pItem)
    6003  {
    -
    6004  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    -
    6005  m_pItem = m_pItem->pNext;
    -
    6006  return *this;
    -
    6007  }
    -
    6008  const_iterator& operator--()
    -
    6009  {
    -
    6010  if(m_pItem != VMA_NULL)
    -
    6011  {
    -
    6012  m_pItem = m_pItem->pPrev;
    -
    6013  }
    -
    6014  else
    -
    6015  {
    -
    6016  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
    -
    6017  m_pItem = m_pList->Back();
    -
    6018  }
    -
    6019  return *this;
    -
    6020  }
    -
    6021 
    -
    6022  const_iterator operator++(int)
    -
    6023  {
    -
    6024  const_iterator result = *this;
    -
    6025  ++*this;
    -
    6026  return result;
    -
    6027  }
    -
    6028  const_iterator operator--(int)
    -
    6029  {
    -
    6030  const_iterator result = *this;
    -
    6031  --*this;
    -
    6032  return result;
    -
    6033  }
    -
    6034 
    -
    6035  bool operator==(const const_iterator& rhs) const
    -
    6036  {
    -
    6037  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    -
    6038  return m_pItem == rhs.m_pItem;
    -
    6039  }
    -
    6040  bool operator!=(const const_iterator& rhs) const
    -
    6041  {
    -
    6042  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    -
    6043  return m_pItem != rhs.m_pItem;
    -
    6044  }
    -
    6045 
    -
    6046  private:
    -
    6047  const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
    -
    6048  m_pList(pList),
    -
    6049  m_pItem(pItem)
    -
    6050  {
    -
    6051  }
    -
    6052 
    -
    6053  const VmaRawList<T>* m_pList;
    -
    6054  const VmaListItem<T>* m_pItem;
    -
    6055 
    -
    6056  friend class VmaList<T, AllocatorT>;
    -
    6057  };
    -
    6058 
    -
    6059  VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
    +
    6004  }
    +
    6005 
    +
    6006  const T& operator*() const
    +
    6007  {
    +
    6008  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    +
    6009  return m_pItem->Value;
    +
    6010  }
    +
    6011  const T* operator->() const
    +
    6012  {
    +
    6013  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    +
    6014  return &m_pItem->Value;
    +
    6015  }
    +
    6016 
    +
    6017  const_iterator& operator++()
    +
    6018  {
    +
    6019  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    +
    6020  m_pItem = m_pItem->pNext;
    +
    6021  return *this;
    +
    6022  }
    +
    6023  const_iterator& operator--()
    +
    6024  {
    +
    6025  if(m_pItem != VMA_NULL)
    +
    6026  {
    +
    6027  m_pItem = m_pItem->pPrev;
    +
    6028  }
    +
    6029  else
    +
    6030  {
    +
    6031  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
    +
    6032  m_pItem = m_pList->Back();
    +
    6033  }
    +
    6034  return *this;
    +
    6035  }
    +
    6036 
    +
    6037  const_iterator operator++(int)
    +
    6038  {
    +
    6039  const_iterator result = *this;
    +
    6040  ++*this;
    +
    6041  return result;
    +
    6042  }
    +
    6043  const_iterator operator--(int)
    +
    6044  {
    +
    6045  const_iterator result = *this;
    +
    6046  --*this;
    +
    6047  return result;
    +
    6048  }
    +
    6049 
    +
    6050  bool operator==(const const_iterator& rhs) const
    +
    6051  {
    +
    6052  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    +
    6053  return m_pItem == rhs.m_pItem;
    +
    6054  }
    +
    6055  bool operator!=(const const_iterator& rhs) const
    +
    6056  {
    +
    6057  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    +
    6058  return m_pItem != rhs.m_pItem;
    +
    6059  }
    6060 
    -
    6061  bool empty() const { return m_RawList.IsEmpty(); }
    -
    6062  size_t size() const { return m_RawList.GetCount(); }
    -
    6063 
    -
    6064  iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
    -
    6065  iterator end() { return iterator(&m_RawList, VMA_NULL); }
    -
    6066 
    -
    6067  const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
    -
    6068  const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
    -
    6069 
    -
    6070  const_iterator begin() const { return cbegin(); }
    -
    6071  const_iterator end() const { return cend(); }
    -
    6072 
    -
    6073  void clear() { m_RawList.Clear(); }
    -
    6074  void push_back(const T& value) { m_RawList.PushBack(value); }
    -
    6075  void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
    -
    6076  iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
    -
    6077 
    -
    6078 private:
    -
    6079  VmaRawList<T> m_RawList;
    -
    6080 };
    +
    6061  private:
    +
    6062  const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
    +
    6063  m_pList(pList),
    +
    6064  m_pItem(pItem)
    +
    6065  {
    +
    6066  }
    +
    6067 
    +
    6068  const VmaRawList<T>* m_pList;
    +
    6069  const VmaListItem<T>* m_pItem;
    +
    6070 
    +
    6071  friend class VmaList<T, AllocatorT>;
    +
    6072  };
    +
    6073 
    +
    6074  VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
    +
    6075 
    +
    6076  bool empty() const { return m_RawList.IsEmpty(); }
    +
    6077  size_t size() const { return m_RawList.GetCount(); }
    +
    6078 
    +
    6079  iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
    +
    6080  iterator end() { return iterator(&m_RawList, VMA_NULL); }
    6081 
    -
    6082 #endif // #if VMA_USE_STL_LIST
    -
    6083 
    -
    6085 // class VmaIntrusiveLinkedList
    -
    6086 
    -
    6087 /*
    -
    6088 Expected interface of ItemTypeTraits:
    -
    6089 struct MyItemTypeTraits
    -
    6090 {
    -
    6091  typedef MyItem ItemType;
    -
    6092  static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; }
    -
    6093  static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; }
    -
    6094  static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; }
    -
    6095  static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; }
    -
    6096 };
    -
    6097 */
    -
    6098 template<typename ItemTypeTraits>
    -
    6099 class VmaIntrusiveLinkedList
    -
    6100 {
    -
    6101 public:
    -
    6102  typedef typename ItemTypeTraits::ItemType ItemType;
    -
    6103  static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
    -
    6104  static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
    -
    6105  // Movable, not copyable.
    -
    6106  VmaIntrusiveLinkedList() { }
    -
    6107  VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
    -
    6108  VmaIntrusiveLinkedList(VmaIntrusiveLinkedList<ItemTypeTraits>&& src) :
    -
    6109  m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
    -
    6110  {
    -
    6111  src.m_Front = src.m_Back = VMA_NULL;
    -
    6112  src.m_Count = 0;
    -
    6113  }
    -
    6114  ~VmaIntrusiveLinkedList()
    -
    6115  {
    -
    6116  VMA_HEAVY_ASSERT(IsEmpty());
    -
    6117  }
    -
    6118  VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
    -
    6119  VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(VmaIntrusiveLinkedList<ItemTypeTraits>&& src)
    -
    6120  {
    -
    6121  if(&src != this)
    -
    6122  {
    -
    6123  VMA_HEAVY_ASSERT(IsEmpty());
    -
    6124  m_Front = src.m_Front;
    -
    6125  m_Back = src.m_Back;
    -
    6126  m_Count = src.m_Count;
    -
    6127  src.m_Front = src.m_Back = VMA_NULL;
    -
    6128  src.m_Count = 0;
    -
    6129  }
    -
    6130  return *this;
    -
    6131  }
    -
    6132  void RemoveAll()
    -
    6133  {
    -
    6134  if(!IsEmpty())
    -
    6135  {
    -
    6136  ItemType* item = m_Back;
    -
    6137  while(item != VMA_NULL)
    -
    6138  {
    -
    6139  ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
    -
    6140  ItemTypeTraits::AccessPrev(item) = VMA_NULL;
    -
    6141  ItemTypeTraits::AccessNext(item) = VMA_NULL;
    -
    6142  item = prevItem;
    -
    6143  }
    -
    6144  m_Front = VMA_NULL;
    -
    6145  m_Back = VMA_NULL;
    -
    6146  m_Count = 0;
    -
    6147  }
    -
    6148  }
    -
    6149  size_t GetCount() const { return m_Count; }
    -
    6150  bool IsEmpty() const { return m_Count == 0; }
    -
    6151  ItemType* Front() { return m_Front; }
    -
    6152  const ItemType* Front() const { return m_Front; }
    -
    6153  ItemType* Back() { return m_Back; }
    -
    6154  const ItemType* Back() const { return m_Back; }
    -
    6155  void PushBack(ItemType* item)
    -
    6156  {
    -
    6157  VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
    -
    6158  if(IsEmpty())
    -
    6159  {
    -
    6160  m_Front = item;
    -
    6161  m_Back = item;
    -
    6162  m_Count = 1;
    -
    6163  }
    -
    6164  else
    -
    6165  {
    -
    6166  ItemTypeTraits::AccessPrev(item) = m_Back;
    -
    6167  ItemTypeTraits::AccessNext(m_Back) = item;
    -
    6168  m_Back = item;
    -
    6169  ++m_Count;
    -
    6170  }
    -
    6171  }
    -
    6172  void PushFront(ItemType* item)
    -
    6173  {
    -
    6174  VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
    -
    6175  if(IsEmpty())
    -
    6176  {
    -
    6177  m_Front = item;
    -
    6178  m_Back = item;
    -
    6179  m_Count = 1;
    -
    6180  }
    -
    6181  else
    -
    6182  {
    -
    6183  ItemTypeTraits::AccessNext(item) = m_Front;
    -
    6184  ItemTypeTraits::AccessPrev(m_Front) = item;
    -
    6185  m_Front = item;
    -
    6186  ++m_Count;
    -
    6187  }
    -
    6188  }
    -
    6189  ItemType* PopBack()
    -
    6190  {
    -
    6191  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    6192  ItemType* const backItem = m_Back;
    -
    6193  ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
    -
    6194  if(prevItem != VMA_NULL)
    -
    6195  {
    -
    6196  ItemTypeTraits::AccessNext(prevItem) = VMA_NULL;
    -
    6197  }
    -
    6198  m_Back = prevItem;
    -
    6199  --m_Count;
    -
    6200  ItemTypeTraits::AccessPrev(backItem) = VMA_NULL;
    -
    6201  ItemTypeTraits::AccessNext(backItem) = VMA_NULL;
    -
    6202  return backItem;
    +
    6082  const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
    +
    6083  const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
    +
    6084 
    +
    6085  const_iterator begin() const { return cbegin(); }
    +
    6086  const_iterator end() const { return cend(); }
    +
    6087 
    +
    6088  void clear() { m_RawList.Clear(); }
    +
    6089  void push_back(const T& value) { m_RawList.PushBack(value); }
    +
    6090  void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
    +
    6091  iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
    +
    6092 
    +
    6093 private:
    +
    6094  VmaRawList<T> m_RawList;
    +
    6095 };
    +
    6096 
    +
    6097 #endif // #if VMA_USE_STL_LIST
    +
    6098 
    +
    6100 // class VmaIntrusiveLinkedList
    +
    6101 
    +
    6102 /*
    +
    6103 Expected interface of ItemTypeTraits:
    +
    6104 struct MyItemTypeTraits
    +
    6105 {
    +
    6106  typedef MyItem ItemType;
    +
    6107  static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; }
    +
    6108  static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; }
    +
    6109  static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; }
    +
    6110  static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; }
    +
    6111 };
    +
    6112 */
    +
    6113 template<typename ItemTypeTraits>
    +
    6114 class VmaIntrusiveLinkedList
    +
    6115 {
    +
    6116 public:
    +
    6117  typedef typename ItemTypeTraits::ItemType ItemType;
    +
    6118  static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
    +
    6119  static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
    +
    6120  // Movable, not copyable.
    +
    6121  VmaIntrusiveLinkedList() { }
    +
    6122  VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
    +
    6123  VmaIntrusiveLinkedList(VmaIntrusiveLinkedList<ItemTypeTraits>&& src) :
    +
    6124  m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
    +
    6125  {
    +
    6126  src.m_Front = src.m_Back = VMA_NULL;
    +
    6127  src.m_Count = 0;
    +
    6128  }
    +
    6129  ~VmaIntrusiveLinkedList()
    +
    6130  {
    +
    6131  VMA_HEAVY_ASSERT(IsEmpty());
    +
    6132  }
    +
    6133  VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
    +
    6134  VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(VmaIntrusiveLinkedList<ItemTypeTraits>&& src)
    +
    6135  {
    +
    6136  if(&src != this)
    +
    6137  {
    +
    6138  VMA_HEAVY_ASSERT(IsEmpty());
    +
    6139  m_Front = src.m_Front;
    +
    6140  m_Back = src.m_Back;
    +
    6141  m_Count = src.m_Count;
    +
    6142  src.m_Front = src.m_Back = VMA_NULL;
    +
    6143  src.m_Count = 0;
    +
    6144  }
    +
    6145  return *this;
    +
    6146  }
    +
    6147  void RemoveAll()
    +
    6148  {
    +
    6149  if(!IsEmpty())
    +
    6150  {
    +
    6151  ItemType* item = m_Back;
    +
    6152  while(item != VMA_NULL)
    +
    6153  {
    +
    6154  ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
    +
    6155  ItemTypeTraits::AccessPrev(item) = VMA_NULL;
    +
    6156  ItemTypeTraits::AccessNext(item) = VMA_NULL;
    +
    6157  item = prevItem;
    +
    6158  }
    +
    6159  m_Front = VMA_NULL;
    +
    6160  m_Back = VMA_NULL;
    +
    6161  m_Count = 0;
    +
    6162  }
    +
    6163  }
    +
    6164  size_t GetCount() const { return m_Count; }
    +
    6165  bool IsEmpty() const { return m_Count == 0; }
    +
    6166  ItemType* Front() { return m_Front; }
    +
    6167  const ItemType* Front() const { return m_Front; }
    +
    6168  ItemType* Back() { return m_Back; }
    +
    6169  const ItemType* Back() const { return m_Back; }
    +
    6170  void PushBack(ItemType* item)
    +
    6171  {
    +
    6172  VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
    +
    6173  if(IsEmpty())
    +
    6174  {
    +
    6175  m_Front = item;
    +
    6176  m_Back = item;
    +
    6177  m_Count = 1;
    +
    6178  }
    +
    6179  else
    +
    6180  {
    +
    6181  ItemTypeTraits::AccessPrev(item) = m_Back;
    +
    6182  ItemTypeTraits::AccessNext(m_Back) = item;
    +
    6183  m_Back = item;
    +
    6184  ++m_Count;
    +
    6185  }
    +
    6186  }
    +
    6187  void PushFront(ItemType* item)
    +
    6188  {
    +
    6189  VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
    +
    6190  if(IsEmpty())
    +
    6191  {
    +
    6192  m_Front = item;
    +
    6193  m_Back = item;
    +
    6194  m_Count = 1;
    +
    6195  }
    +
    6196  else
    +
    6197  {
    +
    6198  ItemTypeTraits::AccessNext(item) = m_Front;
    +
    6199  ItemTypeTraits::AccessPrev(m_Front) = item;
    +
    6200  m_Front = item;
    +
    6201  ++m_Count;
    +
    6202  }
    6203  }
    -
    6204  ItemType* PopFront()
    +
    6204  ItemType* PopBack()
    6205  {
    6206  VMA_HEAVY_ASSERT(m_Count > 0);
    -
    6207  ItemType* const frontItem = m_Front;
    -
    6208  ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
    -
    6209  if(nextItem != VMA_NULL)
    +
    6207  ItemType* const backItem = m_Back;
    +
    6208  ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
    +
    6209  if(prevItem != VMA_NULL)
    6210  {
    -
    6211  ItemTypeTraits::AccessPrev(nextItem) = VMA_NULL;
    +
    6211  ItemTypeTraits::AccessNext(prevItem) = VMA_NULL;
    6212  }
    -
    6213  m_Front = nextItem;
    +
    6213  m_Back = prevItem;
    6214  --m_Count;
    -
    6215  ItemTypeTraits::AccessPrev(frontItem) = VMA_NULL;
    -
    6216  ItemTypeTraits::AccessNext(frontItem) = VMA_NULL;
    -
    6217  return frontItem;
    +
    6215  ItemTypeTraits::AccessPrev(backItem) = VMA_NULL;
    +
    6216  ItemTypeTraits::AccessNext(backItem) = VMA_NULL;
    +
    6217  return backItem;
    6218  }
    -
    6219 
    -
    6220  // MyItem can be null - it means PushBack.
    -
    6221  void InsertBefore(ItemType* existingItem, ItemType* newItem)
    -
    6222  {
    -
    6223  VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
    -
    6224  if(existingItem != VMA_NULL)
    +
    6219  ItemType* PopFront()
    +
    6220  {
    +
    6221  VMA_HEAVY_ASSERT(m_Count > 0);
    +
    6222  ItemType* const frontItem = m_Front;
    +
    6223  ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
    +
    6224  if(nextItem != VMA_NULL)
    6225  {
    -
    6226  ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
    -
    6227  ItemTypeTraits::AccessPrev(newItem) = prevItem;
    -
    6228  ItemTypeTraits::AccessNext(newItem) = existingItem;
    -
    6229  ItemTypeTraits::AccessPrev(existingItem) = newItem;
    -
    6230  if(prevItem != VMA_NULL)
    -
    6231  {
    -
    6232  ItemTypeTraits::AccessNext(prevItem) = newItem;
    -
    6233  }
    -
    6234  else
    -
    6235  {
    -
    6236  VMA_HEAVY_ASSERT(m_Front == existingItem);
    -
    6237  m_Front = newItem;
    -
    6238  }
    -
    6239  ++m_Count;
    -
    6240  }
    -
    6241  else
    -
    6242  PushBack(newItem);
    -
    6243  }
    -
    6244  // MyItem can be null - it means PushFront.
    -
    6245  void InsertAfter(ItemType* existingItem, ItemType* newItem)
    -
    6246  {
    -
    6247  VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
    -
    6248  if(existingItem != VMA_NULL)
    -
    6249  {
    -
    6250  ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
    -
    6251  ItemTypeTraits::AccessNext(newItem) = nextItem;
    -
    6252  ItemTypeTraits::AccessPrev(newItem) = existingItem;
    -
    6253  ItemTypeTraits::AccessNext(existingItem) = newItem;
    -
    6254  if(nextItem != VMA_NULL)
    -
    6255  {
    -
    6256  ItemTypeTraits::AccessPrev(nextItem) = newItem;
    -
    6257  }
    -
    6258  else
    -
    6259  {
    -
    6260  VMA_HEAVY_ASSERT(m_Back == existingItem);
    -
    6261  m_Back = newItem;
    -
    6262  }
    -
    6263  ++m_Count;
    -
    6264  }
    -
    6265  else
    -
    6266  return PushFront(newItem);
    -
    6267  }
    -
    6268  void Remove(ItemType* item)
    -
    6269  {
    -
    6270  VMA_HEAVY_ASSERT(item != VMA_NULL && m_Count > 0);
    -
    6271  if(ItemTypeTraits::GetPrev(item) != VMA_NULL)
    -
    6272  {
    -
    6273  ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
    -
    6274  }
    -
    6275  else
    -
    6276  {
    -
    6277  VMA_HEAVY_ASSERT(m_Front == item);
    -
    6278  m_Front = ItemTypeTraits::GetNext(item);
    +
    6226  ItemTypeTraits::AccessPrev(nextItem) = VMA_NULL;
    +
    6227  }
    +
    6228  m_Front = nextItem;
    +
    6229  --m_Count;
    +
    6230  ItemTypeTraits::AccessPrev(frontItem) = VMA_NULL;
    +
    6231  ItemTypeTraits::AccessNext(frontItem) = VMA_NULL;
    +
    6232  return frontItem;
    +
    6233  }
    +
    6234 
    +
    6235  // MyItem can be null - it means PushBack.
    +
    6236  void InsertBefore(ItemType* existingItem, ItemType* newItem)
    +
    6237  {
    +
    6238  VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
    +
    6239  if(existingItem != VMA_NULL)
    +
    6240  {
    +
    6241  ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
    +
    6242  ItemTypeTraits::AccessPrev(newItem) = prevItem;
    +
    6243  ItemTypeTraits::AccessNext(newItem) = existingItem;
    +
    6244  ItemTypeTraits::AccessPrev(existingItem) = newItem;
    +
    6245  if(prevItem != VMA_NULL)
    +
    6246  {
    +
    6247  ItemTypeTraits::AccessNext(prevItem) = newItem;
    +
    6248  }
    +
    6249  else
    +
    6250  {
    +
    6251  VMA_HEAVY_ASSERT(m_Front == existingItem);
    +
    6252  m_Front = newItem;
    +
    6253  }
    +
    6254  ++m_Count;
    +
    6255  }
    +
    6256  else
    +
    6257  PushBack(newItem);
    +
    6258  }
    +
    6259  // MyItem can be null - it means PushFront.
    +
    6260  void InsertAfter(ItemType* existingItem, ItemType* newItem)
    +
    6261  {
    +
    6262  VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
    +
    6263  if(existingItem != VMA_NULL)
    +
    6264  {
    +
    6265  ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
    +
    6266  ItemTypeTraits::AccessNext(newItem) = nextItem;
    +
    6267  ItemTypeTraits::AccessPrev(newItem) = existingItem;
    +
    6268  ItemTypeTraits::AccessNext(existingItem) = newItem;
    +
    6269  if(nextItem != VMA_NULL)
    +
    6270  {
    +
    6271  ItemTypeTraits::AccessPrev(nextItem) = newItem;
    +
    6272  }
    +
    6273  else
    +
    6274  {
    +
    6275  VMA_HEAVY_ASSERT(m_Back == existingItem);
    +
    6276  m_Back = newItem;
    +
    6277  }
    +
    6278  ++m_Count;
    6279  }
    -
    6280 
    -
    6281  if(ItemTypeTraits::GetNext(item) != VMA_NULL)
    -
    6282  {
    -
    6283  ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
    -
    6284  }
    -
    6285  else
    -
    6286  {
    -
    6287  VMA_HEAVY_ASSERT(m_Back == item);
    -
    6288  m_Back = ItemTypeTraits::GetPrev(item);
    +
    6280  else
    +
    6281  return PushFront(newItem);
    +
    6282  }
    +
    6283  void Remove(ItemType* item)
    +
    6284  {
    +
    6285  VMA_HEAVY_ASSERT(item != VMA_NULL && m_Count > 0);
    +
    6286  if(ItemTypeTraits::GetPrev(item) != VMA_NULL)
    +
    6287  {
    +
    6288  ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
    6289  }
    -
    6290  ItemTypeTraits::AccessPrev(item) = VMA_NULL;
    -
    6291  ItemTypeTraits::AccessNext(item) = VMA_NULL;
    -
    6292  --m_Count;
    -
    6293  }
    -
    6294 private:
    -
    6295  ItemType* m_Front = VMA_NULL;
    -
    6296  ItemType* m_Back = VMA_NULL;
    -
    6297  size_t m_Count = 0;
    -
    6298 };
    -
    6299 
    -
    6301 // class VmaMap
    -
    6302 
    -
    6303 // Unused in this version.
    -
    6304 #if 0
    -
    6305 
    -
    6306 #if VMA_USE_STL_UNORDERED_MAP
    -
    6307 
    -
    6308 #define VmaPair std::pair
    -
    6309 
    -
    6310 #define VMA_MAP_TYPE(KeyT, ValueT) \
    -
    6311  std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
    -
    6312 
    -
    6313 #else // #if VMA_USE_STL_UNORDERED_MAP
    +
    6290  else
    +
    6291  {
    +
    6292  VMA_HEAVY_ASSERT(m_Front == item);
    +
    6293  m_Front = ItemTypeTraits::GetNext(item);
    +
    6294  }
    +
    6295 
    +
    6296  if(ItemTypeTraits::GetNext(item) != VMA_NULL)
    +
    6297  {
    +
    6298  ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
    +
    6299  }
    +
    6300  else
    +
    6301  {
    +
    6302  VMA_HEAVY_ASSERT(m_Back == item);
    +
    6303  m_Back = ItemTypeTraits::GetPrev(item);
    +
    6304  }
    +
    6305  ItemTypeTraits::AccessPrev(item) = VMA_NULL;
    +
    6306  ItemTypeTraits::AccessNext(item) = VMA_NULL;
    +
    6307  --m_Count;
    +
    6308  }
    +
    6309 private:
    +
    6310  ItemType* m_Front = VMA_NULL;
    +
    6311  ItemType* m_Back = VMA_NULL;
    +
    6312  size_t m_Count = 0;
    +
    6313 };
    6314 
    -
    6315 template<typename T1, typename T2>
    -
    6316 struct VmaPair
    -
    6317 {
    -
    6318  T1 first;
    -
    6319  T2 second;
    +
    6316 // class VmaMap
    +
    6317 
    +
    6318 // Unused in this version.
    +
    6319 #if 0
    6320 
    -
    6321  VmaPair() : first(), second() { }
    -
    6322  VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
    -
    6323 };
    +
    6321 #if VMA_USE_STL_UNORDERED_MAP
    +
    6322 
    +
    6323 #define VmaPair std::pair
    6324 
    -
    6325 /* Class compatible with subset of interface of std::unordered_map.
    -
    6326 KeyT, ValueT must be POD because they will be stored in VmaVector.
    -
    6327 */
    -
    6328 template<typename KeyT, typename ValueT>
    -
    6329 class VmaMap
    -
    6330 {
    -
    6331 public:
    -
    6332  typedef VmaPair<KeyT, ValueT> PairType;
    -
    6333  typedef PairType* iterator;
    -
    6334 
    -
    6335  VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
    -
    6336 
    -
    6337  iterator begin() { return m_Vector.begin(); }
    -
    6338  iterator end() { return m_Vector.end(); }
    +
    6325 #define VMA_MAP_TYPE(KeyT, ValueT) \
    +
    6326  std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
    +
    6327 
    +
    6328 #else // #if VMA_USE_STL_UNORDERED_MAP
    +
    6329 
    +
    6330 template<typename T1, typename T2>
    +
    6331 struct VmaPair
    +
    6332 {
    +
    6333  T1 first;
    +
    6334  T2 second;
    +
    6335 
    +
    6336  VmaPair() : first(), second() { }
    +
    6337  VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
    +
    6338 };
    6339 
    -
    6340  void insert(const PairType& pair);
    -
    6341  iterator find(const KeyT& key);
    -
    6342  void erase(iterator it);
    -
    6343 
    -
    6344 private:
    -
    6345  VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
    -
    6346 };
    -
    6347 
    -
    6348 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
    +
    6340 /* Class compatible with subset of interface of std::unordered_map.
    +
    6341 KeyT, ValueT must be POD because they will be stored in VmaVector.
    +
    6342 */
    +
    6343 template<typename KeyT, typename ValueT>
    +
    6344 class VmaMap
    +
    6345 {
    +
    6346 public:
    +
    6347  typedef VmaPair<KeyT, ValueT> PairType;
    +
    6348  typedef PairType* iterator;
    6349 
    -
    6350 template<typename FirstT, typename SecondT>
    -
    6351 struct VmaPairFirstLess
    -
    6352 {
    -
    6353  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
    -
    6354  {
    -
    6355  return lhs.first < rhs.first;
    -
    6356  }
    -
    6357  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
    -
    6358  {
    -
    6359  return lhs.first < rhsFirst;
    -
    6360  }
    +
    6350  VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
    +
    6351 
    +
    6352  iterator begin() { return m_Vector.begin(); }
    +
    6353  iterator end() { return m_Vector.end(); }
    +
    6354 
    +
    6355  void insert(const PairType& pair);
    +
    6356  iterator find(const KeyT& key);
    +
    6357  void erase(iterator it);
    +
    6358 
    +
    6359 private:
    +
    6360  VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
    6361 };
    6362 
    -
    6363 template<typename KeyT, typename ValueT>
    -
    6364 void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
    -
    6365 {
    -
    6366  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    -
    6367  m_Vector.data(),
    -
    6368  m_Vector.data() + m_Vector.size(),
    -
    6369  pair,
    -
    6370  VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
    -
    6371  VmaVectorInsert(m_Vector, indexToInsert, pair);
    -
    6372 }
    -
    6373 
    -
    6374 template<typename KeyT, typename ValueT>
    -
    6375 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
    -
    6376 {
    -
    6377  PairType* it = VmaBinaryFindFirstNotLess(
    -
    6378  m_Vector.data(),
    -
    6379  m_Vector.data() + m_Vector.size(),
    -
    6380  key,
    -
    6381  VmaPairFirstLess<KeyT, ValueT>());
    -
    6382  if((it != m_Vector.end()) && (it->first == key))
    -
    6383  {
    -
    6384  return it;
    -
    6385  }
    -
    6386  else
    -
    6387  {
    -
    6388  return m_Vector.end();
    -
    6389  }
    -
    6390 }
    -
    6391 
    -
    6392 template<typename KeyT, typename ValueT>
    -
    6393 void VmaMap<KeyT, ValueT>::erase(iterator it)
    -
    6394 {
    -
    6395  VmaVectorRemove(m_Vector, it - m_Vector.begin());
    -
    6396 }
    -
    6397 
    -
    6398 #endif // #if VMA_USE_STL_UNORDERED_MAP
    -
    6399 
    -
    6400 #endif // #if 0
    -
    6401 
    -
    6403 
    -
    6404 class VmaDeviceMemoryBlock;
    -
    6405 
    -
    6406 enum VMA_CACHE_OPERATION { VMA_CACHE_FLUSH, VMA_CACHE_INVALIDATE };
    -
    6407 
    -
    6408 struct VmaAllocation_T
    +
    6363 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
    +
    6364 
    +
    6365 template<typename FirstT, typename SecondT>
    +
    6366 struct VmaPairFirstLess
    +
    6367 {
    +
    6368  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
    +
    6369  {
    +
    6370  return lhs.first < rhs.first;
    +
    6371  }
    +
    6372  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
    +
    6373  {
    +
    6374  return lhs.first < rhsFirst;
    +
    6375  }
    +
    6376 };
    +
    6377 
    +
    6378 template<typename KeyT, typename ValueT>
    +
    6379 void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
    +
    6380 {
    +
    6381  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    +
    6382  m_Vector.data(),
    +
    6383  m_Vector.data() + m_Vector.size(),
    +
    6384  pair,
    +
    6385  VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
    +
    6386  VmaVectorInsert(m_Vector, indexToInsert, pair);
    +
    6387 }
    +
    6388 
    +
    6389 template<typename KeyT, typename ValueT>
    +
    6390 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
    +
    6391 {
    +
    6392  PairType* it = VmaBinaryFindFirstNotLess(
    +
    6393  m_Vector.data(),
    +
    6394  m_Vector.data() + m_Vector.size(),
    +
    6395  key,
    +
    6396  VmaPairFirstLess<KeyT, ValueT>());
    +
    6397  if((it != m_Vector.end()) && (it->first == key))
    +
    6398  {
    +
    6399  return it;
    +
    6400  }
    +
    6401  else
    +
    6402  {
    +
    6403  return m_Vector.end();
    +
    6404  }
    +
    6405 }
    +
    6406 
    +
    6407 template<typename KeyT, typename ValueT>
    +
    6408 void VmaMap<KeyT, ValueT>::erase(iterator it)
    6409 {
    -
    6410 private:
    -
    6411  static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
    +
    6410  VmaVectorRemove(m_Vector, it - m_Vector.begin());
    +
    6411 }
    6412 
    -
    6413  enum FLAGS
    -
    6414  {
    -
    6415  FLAG_USER_DATA_STRING = 0x01,
    -
    6416  };
    -
    6417 
    -
    6418 public:
    -
    6419  enum ALLOCATION_TYPE
    -
    6420  {
    -
    6421  ALLOCATION_TYPE_NONE,
    -
    6422  ALLOCATION_TYPE_BLOCK,
    -
    6423  ALLOCATION_TYPE_DEDICATED,
    -
    6424  };
    -
    6425 
    -
    6426  /*
    -
    6427  This struct is allocated using VmaPoolAllocator.
    -
    6428  */
    -
    6429 
    -
    6430  VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) :
    -
    6431  m_Alignment{1},
    -
    6432  m_Size{0},
    -
    6433  m_pUserData{VMA_NULL},
    -
    6434  m_LastUseFrameIndex{currentFrameIndex},
    -
    6435  m_MemoryTypeIndex{0},
    -
    6436  m_Type{(uint8_t)ALLOCATION_TYPE_NONE},
    -
    6437  m_SuballocationType{(uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN},
    -
    6438  m_MapCount{0},
    -
    6439  m_Flags{userDataString ? (uint8_t)FLAG_USER_DATA_STRING : (uint8_t)0}
    -
    6440  {
    -
    6441 #if VMA_STATS_STRING_ENABLED
    -
    6442  m_CreationFrameIndex = currentFrameIndex;
    -
    6443  m_BufferImageUsage = 0;
    -
    6444 #endif
    -
    6445  }
    -
    6446 
    -
    6447  ~VmaAllocation_T()
    -
    6448  {
    -
    6449  VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction.");
    -
    6450 
    -
    6451  // Check if owned string was freed.
    -
    6452  VMA_ASSERT(m_pUserData == VMA_NULL);
    -
    6453  }
    -
    6454 
    -
    6455  void InitBlockAllocation(
    -
    6456  VmaDeviceMemoryBlock* block,
    -
    6457  VkDeviceSize offset,
    -
    6458  VkDeviceSize alignment,
    -
    6459  VkDeviceSize size,
    -
    6460  uint32_t memoryTypeIndex,
    -
    6461  VmaSuballocationType suballocationType,
    -
    6462  bool mapped,
    -
    6463  bool canBecomeLost)
    -
    6464  {
    -
    6465  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    -
    6466  VMA_ASSERT(block != VMA_NULL);
    -
    6467  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
    -
    6468  m_Alignment = alignment;
    -
    6469  m_Size = size;
    -
    6470  m_MemoryTypeIndex = memoryTypeIndex;
    -
    6471  m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
    -
    6472  m_SuballocationType = (uint8_t)suballocationType;
    -
    6473  m_BlockAllocation.m_Block = block;
    -
    6474  m_BlockAllocation.m_Offset = offset;
    -
    6475  m_BlockAllocation.m_CanBecomeLost = canBecomeLost;
    -
    6476  }
    -
    6477 
    -
    6478  void InitLost()
    +
    6413 #endif // #if VMA_USE_STL_UNORDERED_MAP
    +
    6414 
    +
    6415 #endif // #if 0
    +
    6416 
    +
    6418 
    +
    6419 class VmaDeviceMemoryBlock;
    +
    6420 
    +
    6421 enum VMA_CACHE_OPERATION { VMA_CACHE_FLUSH, VMA_CACHE_INVALIDATE };
    +
    6422 
    +
    6423 struct VmaAllocation_T
    +
    6424 {
    +
    6425 private:
    +
    6426  static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
    +
    6427 
    +
    6428  enum FLAGS
    +
    6429  {
    +
    6430  FLAG_USER_DATA_STRING = 0x01,
    +
    6431  };
    +
    6432 
    +
    6433 public:
    +
    6434  enum ALLOCATION_TYPE
    +
    6435  {
    +
    6436  ALLOCATION_TYPE_NONE,
    +
    6437  ALLOCATION_TYPE_BLOCK,
    +
    6438  ALLOCATION_TYPE_DEDICATED,
    +
    6439  };
    +
    6440 
    +
    6441  /*
    +
    6442  This struct is allocated using VmaPoolAllocator.
    +
    6443  */
    +
    6444 
    +
    6445  VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) :
    +
    6446  m_Alignment{1},
    +
    6447  m_Size{0},
    +
    6448  m_pUserData{VMA_NULL},
    +
    6449  m_LastUseFrameIndex{currentFrameIndex},
    +
    6450  m_MemoryTypeIndex{0},
    +
    6451  m_Type{(uint8_t)ALLOCATION_TYPE_NONE},
    +
    6452  m_SuballocationType{(uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN},
    +
    6453  m_MapCount{0},
    +
    6454  m_Flags{userDataString ? (uint8_t)FLAG_USER_DATA_STRING : (uint8_t)0}
    +
    6455  {
    +
    6456 #if VMA_STATS_STRING_ENABLED
    +
    6457  m_CreationFrameIndex = currentFrameIndex;
    +
    6458  m_BufferImageUsage = 0;
    +
    6459 #endif
    +
    6460  }
    +
    6461 
    +
    6462  ~VmaAllocation_T()
    +
    6463  {
    +
    6464  VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction.");
    +
    6465 
    +
    6466  // Check if owned string was freed.
    +
    6467  VMA_ASSERT(m_pUserData == VMA_NULL);
    +
    6468  }
    +
    6469 
    +
    6470  void InitBlockAllocation(
    +
    6471  VmaDeviceMemoryBlock* block,
    +
    6472  VkDeviceSize offset,
    +
    6473  VkDeviceSize alignment,
    +
    6474  VkDeviceSize size,
    +
    6475  uint32_t memoryTypeIndex,
    +
    6476  VmaSuballocationType suballocationType,
    +
    6477  bool mapped,
    +
    6478  bool canBecomeLost)
    6479  {
    6480  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    -
    6481  VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
    +
    6481  VMA_ASSERT(block != VMA_NULL);
    6482  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
    -
    6483  m_MemoryTypeIndex = 0;
    -
    6484  m_BlockAllocation.m_Block = VMA_NULL;
    -
    6485  m_BlockAllocation.m_Offset = 0;
    -
    6486  m_BlockAllocation.m_CanBecomeLost = true;
    -
    6487  }
    -
    6488 
    -
    6489  void ChangeBlockAllocation(
    -
    6490  VmaAllocator hAllocator,
    -
    6491  VmaDeviceMemoryBlock* block,
    -
    6492  VkDeviceSize offset);
    -
    6493 
    -
    6494  void ChangeOffset(VkDeviceSize newOffset);
    -
    6495 
    -
    6496  // pMappedData not null means allocation is created with MAPPED flag.
    -
    6497  void InitDedicatedAllocation(
    -
    6498  uint32_t memoryTypeIndex,
    -
    6499  VkDeviceMemory hMemory,
    -
    6500  VmaSuballocationType suballocationType,
    -
    6501  void* pMappedData,
    -
    6502  VkDeviceSize size)
    -
    6503  {
    -
    6504  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    -
    6505  VMA_ASSERT(hMemory != VK_NULL_HANDLE);
    -
    6506  m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
    -
    6507  m_Alignment = 0;
    -
    6508  m_Size = size;
    -
    6509  m_MemoryTypeIndex = memoryTypeIndex;
    -
    6510  m_SuballocationType = (uint8_t)suballocationType;
    -
    6511  m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
    -
    6512  m_DedicatedAllocation.m_hMemory = hMemory;
    -
    6513  m_DedicatedAllocation.m_pMappedData = pMappedData;
    -
    6514  m_DedicatedAllocation.m_Prev = VMA_NULL;
    -
    6515  m_DedicatedAllocation.m_Next = VMA_NULL;
    -
    6516  }
    -
    6517 
    -
    6518  ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
    -
    6519  VkDeviceSize GetAlignment() const { return m_Alignment; }
    -
    6520  VkDeviceSize GetSize() const { return m_Size; }
    -
    6521  bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; }
    -
    6522  void* GetUserData() const { return m_pUserData; }
    -
    6523  void SetUserData(VmaAllocator hAllocator, void* pUserData);
    -
    6524  VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; }
    -
    6525 
    -
    6526  VmaDeviceMemoryBlock* GetBlock() const
    -
    6527  {
    -
    6528  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    -
    6529  return m_BlockAllocation.m_Block;
    -
    6530  }
    -
    6531  VkDeviceSize GetOffset() const;
    -
    6532  VkDeviceMemory GetMemory() const;
    -
    6533  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
    -
    6534  bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
    -
    6535  void* GetMappedData() const;
    -
    6536  bool CanBecomeLost() const;
    -
    6537 
    -
    6538  uint32_t GetLastUseFrameIndex() const
    -
    6539  {
    -
    6540  return m_LastUseFrameIndex.load();
    -
    6541  }
    -
    6542  bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired)
    -
    6543  {
    -
    6544  return m_LastUseFrameIndex.compare_exchange_weak(expected, desired);
    +
    6483  m_Alignment = alignment;
    +
    6484  m_Size = size;
    +
    6485  m_MemoryTypeIndex = memoryTypeIndex;
    +
    6486  m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
    +
    6487  m_SuballocationType = (uint8_t)suballocationType;
    +
    6488  m_BlockAllocation.m_Block = block;
    +
    6489  m_BlockAllocation.m_Offset = offset;
    +
    6490  m_BlockAllocation.m_CanBecomeLost = canBecomeLost;
    +
    6491  }
    +
    6492 
    +
    6493  void InitLost()
    +
    6494  {
    +
    6495  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    +
    6496  VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
    +
    6497  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
    +
    6498  m_MemoryTypeIndex = 0;
    +
    6499  m_BlockAllocation.m_Block = VMA_NULL;
    +
    6500  m_BlockAllocation.m_Offset = 0;
    +
    6501  m_BlockAllocation.m_CanBecomeLost = true;
    +
    6502  }
    +
    6503 
    +
    6504  void ChangeBlockAllocation(
    +
    6505  VmaAllocator hAllocator,
    +
    6506  VmaDeviceMemoryBlock* block,
    +
    6507  VkDeviceSize offset);
    +
    6508 
    +
    6509  void ChangeOffset(VkDeviceSize newOffset);
    +
    6510 
    +
    6511  // pMappedData not null means allocation is created with MAPPED flag.
    +
    6512  void InitDedicatedAllocation(
    +
    6513  uint32_t memoryTypeIndex,
    +
    6514  VkDeviceMemory hMemory,
    +
    6515  VmaSuballocationType suballocationType,
    +
    6516  void* pMappedData,
    +
    6517  VkDeviceSize size)
    +
    6518  {
    +
    6519  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    +
    6520  VMA_ASSERT(hMemory != VK_NULL_HANDLE);
    +
    6521  m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
    +
    6522  m_Alignment = 0;
    +
    6523  m_Size = size;
    +
    6524  m_MemoryTypeIndex = memoryTypeIndex;
    +
    6525  m_SuballocationType = (uint8_t)suballocationType;
    +
    6526  m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
    +
    6527  m_DedicatedAllocation.m_hMemory = hMemory;
    +
    6528  m_DedicatedAllocation.m_pMappedData = pMappedData;
    +
    6529  m_DedicatedAllocation.m_Prev = VMA_NULL;
    +
    6530  m_DedicatedAllocation.m_Next = VMA_NULL;
    +
    6531  }
    +
    6532 
    +
    6533  ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
    +
    6534  VkDeviceSize GetAlignment() const { return m_Alignment; }
    +
    6535  VkDeviceSize GetSize() const { return m_Size; }
    +
    6536  bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; }
    +
    6537  void* GetUserData() const { return m_pUserData; }
    +
    6538  void SetUserData(VmaAllocator hAllocator, void* pUserData);
    +
    6539  VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; }
    +
    6540 
    +
    6541  VmaDeviceMemoryBlock* GetBlock() const
    +
    6542  {
    +
    6543  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    +
    6544  return m_BlockAllocation.m_Block;
    6545  }
    -
    6546  /*
    -
    6547  - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex,
    -
    6548  makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true.
    -
    6549  - Else, returns false.
    -
    6550 
    -
    6551  If hAllocation is already lost, assert - you should not call it then.
    -
    6552  If hAllocation was not created with CAN_BECOME_LOST_BIT, assert.
    -
    6553  */
    -
    6554  bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    -
    6555 
    -
    6556  void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo)
    -
    6557  {
    -
    6558  VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED);
    -
    6559  outInfo.blockCount = 1;
    -
    6560  outInfo.allocationCount = 1;
    -
    6561  outInfo.unusedRangeCount = 0;
    -
    6562  outInfo.usedBytes = m_Size;
    -
    6563  outInfo.unusedBytes = 0;
    -
    6564  outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size;
    -
    6565  outInfo.unusedRangeSizeMin = UINT64_MAX;
    -
    6566  outInfo.unusedRangeSizeMax = 0;
    -
    6567  }
    -
    6568 
    -
    6569  void BlockAllocMap();
    -
    6570  void BlockAllocUnmap();
    -
    6571  VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData);
    -
    6572  void DedicatedAllocUnmap(VmaAllocator hAllocator);
    -
    6573 
    -
    6574 #if VMA_STATS_STRING_ENABLED
    -
    6575  uint32_t GetCreationFrameIndex() const { return m_CreationFrameIndex; }
    -
    6576  uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; }
    -
    6577 
    -
    6578  void InitBufferImageUsage(uint32_t bufferImageUsage)
    -
    6579  {
    -
    6580  VMA_ASSERT(m_BufferImageUsage == 0);
    -
    6581  m_BufferImageUsage = bufferImageUsage;
    +
    6546  VkDeviceSize GetOffset() const;
    +
    6547  VkDeviceMemory GetMemory() const;
    +
    6548  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
    +
    6549  bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
    +
    6550  void* GetMappedData() const;
    +
    6551  bool CanBecomeLost() const;
    +
    6552 
    +
    6553  uint32_t GetLastUseFrameIndex() const
    +
    6554  {
    +
    6555  return m_LastUseFrameIndex.load();
    +
    6556  }
    +
    6557  bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired)
    +
    6558  {
    +
    6559  return m_LastUseFrameIndex.compare_exchange_weak(expected, desired);
    +
    6560  }
    +
    6561  /*
    +
    6562  - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex,
    +
    6563  makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true.
    +
    6564  - Else, returns false.
    +
    6565 
    +
    6566  If hAllocation is already lost, assert - you should not call it then.
    +
    6567  If hAllocation was not created with CAN_BECOME_LOST_BIT, assert.
    +
    6568  */
    +
    6569  bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    +
    6570 
    +
    6571  void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo)
    +
    6572  {
    +
    6573  VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED);
    +
    6574  outInfo.blockCount = 1;
    +
    6575  outInfo.allocationCount = 1;
    +
    6576  outInfo.unusedRangeCount = 0;
    +
    6577  outInfo.usedBytes = m_Size;
    +
    6578  outInfo.unusedBytes = 0;
    +
    6579  outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size;
    +
    6580  outInfo.unusedRangeSizeMin = UINT64_MAX;
    +
    6581  outInfo.unusedRangeSizeMax = 0;
    6582  }
    6583 
    -
    6584  void PrintParameters(class VmaJsonWriter& json) const;
    -
    6585 #endif
    -
    6586 
    -
    6587 private:
    -
    6588  VkDeviceSize m_Alignment;
    -
    6589  VkDeviceSize m_Size;
    -
    6590  void* m_pUserData;
    -
    6591  VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
    -
    6592  uint32_t m_MemoryTypeIndex;
    -
    6593  uint8_t m_Type; // ALLOCATION_TYPE
    -
    6594  uint8_t m_SuballocationType; // VmaSuballocationType
    -
    6595  // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
    -
    6596  // Bits with mask 0x7F are reference counter for vmaMapMemory()/vmaUnmapMemory().
    -
    6597  uint8_t m_MapCount;
    -
    6598  uint8_t m_Flags; // enum FLAGS
    -
    6599 
    -
    6600  // Allocation out of VmaDeviceMemoryBlock.
    -
    6601  struct BlockAllocation
    -
    6602  {
    -
    6603  VmaDeviceMemoryBlock* m_Block;
    -
    6604  VkDeviceSize m_Offset;
    -
    6605  bool m_CanBecomeLost;
    -
    6606  };
    -
    6607 
    -
    6608  // Allocation for an object that has its own private VkDeviceMemory.
    -
    6609  struct DedicatedAllocation
    -
    6610  {
    -
    6611  VkDeviceMemory m_hMemory;
    -
    6612  void* m_pMappedData; // Not null means memory is mapped.
    -
    6613  VmaAllocation_T* m_Prev;
    -
    6614  VmaAllocation_T* m_Next;
    -
    6615  };
    -
    6616 
    -
    6617  union
    -
    6618  {
    -
    6619  // Allocation out of VmaDeviceMemoryBlock.
    -
    6620  BlockAllocation m_BlockAllocation;
    -
    6621  // Allocation for an object that has its own private VkDeviceMemory.
    -
    6622  DedicatedAllocation m_DedicatedAllocation;
    -
    6623  };
    -
    6624 
    -
    6625 #if VMA_STATS_STRING_ENABLED
    -
    6626  uint32_t m_CreationFrameIndex;
    -
    6627  uint32_t m_BufferImageUsage; // 0 if unknown.
    -
    6628 #endif
    -
    6629 
    -
    6630  void FreeUserDataString(VmaAllocator hAllocator);
    +
    6584  void BlockAllocMap();
    +
    6585  void BlockAllocUnmap();
    +
    6586  VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData);
    +
    6587  void DedicatedAllocUnmap(VmaAllocator hAllocator);
    +
    6588 
    +
    6589 #if VMA_STATS_STRING_ENABLED
    +
    6590  uint32_t GetCreationFrameIndex() const { return m_CreationFrameIndex; }
    +
    6591  uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; }
    +
    6592 
    +
    6593  void InitBufferImageUsage(uint32_t bufferImageUsage)
    +
    6594  {
    +
    6595  VMA_ASSERT(m_BufferImageUsage == 0);
    +
    6596  m_BufferImageUsage = bufferImageUsage;
    +
    6597  }
    +
    6598 
    +
    6599  void PrintParameters(class VmaJsonWriter& json) const;
    +
    6600 #endif
    +
    6601 
    +
    6602 private:
    +
    6603  VkDeviceSize m_Alignment;
    +
    6604  VkDeviceSize m_Size;
    +
    6605  void* m_pUserData;
    +
    6606  VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
    +
    6607  uint32_t m_MemoryTypeIndex;
    +
    6608  uint8_t m_Type; // ALLOCATION_TYPE
    +
    6609  uint8_t m_SuballocationType; // VmaSuballocationType
    +
    6610  // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
    +
    6611  // Bits with mask 0x7F are reference counter for vmaMapMemory()/vmaUnmapMemory().
    +
    6612  uint8_t m_MapCount;
    +
    6613  uint8_t m_Flags; // enum FLAGS
    +
    6614 
    +
    6615  // Allocation out of VmaDeviceMemoryBlock.
    +
    6616  struct BlockAllocation
    +
    6617  {
    +
    6618  VmaDeviceMemoryBlock* m_Block;
    +
    6619  VkDeviceSize m_Offset;
    +
    6620  bool m_CanBecomeLost;
    +
    6621  };
    +
    6622 
    +
    6623  // Allocation for an object that has its own private VkDeviceMemory.
    +
    6624  struct DedicatedAllocation
    +
    6625  {
    +
    6626  VkDeviceMemory m_hMemory;
    +
    6627  void* m_pMappedData; // Not null means memory is mapped.
    +
    6628  VmaAllocation_T* m_Prev;
    +
    6629  VmaAllocation_T* m_Next;
    +
    6630  };
    6631 
    -
    6632  friend struct VmaDedicatedAllocationListItemTraits;
    -
    6633 };
    -
    6634 
    -
    6635 struct VmaDedicatedAllocationListItemTraits
    -
    6636 {
    -
    6637  typedef VmaAllocation_T ItemType;
    -
    6638  static ItemType* GetPrev(const ItemType* item)
    -
    6639  {
    -
    6640  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    -
    6641  return item->m_DedicatedAllocation.m_Prev;
    -
    6642  }
    -
    6643  static ItemType* GetNext(const ItemType* item)
    -
    6644  {
    -
    6645  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    -
    6646  return item->m_DedicatedAllocation.m_Next;
    -
    6647  }
    -
    6648  static ItemType*& AccessPrev(ItemType* item)
    -
    6649  {
    -
    6650  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    -
    6651  return item->m_DedicatedAllocation.m_Prev;
    -
    6652  }
    -
    6653  static ItemType*& AccessNext(ItemType* item){
    -
    6654  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    -
    6655  return item->m_DedicatedAllocation.m_Next;
    -
    6656  }
    -
    6657 };
    -
    6658 
    -
    6659 /*
    -
    6660 Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as
    -
    6661 allocated memory block or free.
    -
    6662 */
    -
    6663 struct VmaSuballocation
    -
    6664 {
    -
    6665  VkDeviceSize offset;
    -
    6666  VkDeviceSize size;
    -
    6667  VmaAllocation hAllocation;
    -
    6668  VmaSuballocationType type;
    -
    6669 };
    -
    6670 
    -
    6671 // Comparator for offsets.
    -
    6672 struct VmaSuballocationOffsetLess
    -
    6673 {
    -
    6674  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
    -
    6675  {
    -
    6676  return lhs.offset < rhs.offset;
    -
    6677  }
    -
    6678 };
    -
    6679 struct VmaSuballocationOffsetGreater
    -
    6680 {
    -
    6681  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
    -
    6682  {
    -
    6683  return lhs.offset > rhs.offset;
    -
    6684  }
    -
    6685 };
    -
    6686 
    -
    6687 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
    -
    6688 
    -
    6689 // Cost of one additional allocation lost, as equivalent in bytes.
    -
    6690 static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576;
    -
    6691 
    -
    6692 enum class VmaAllocationRequestType
    -
    6693 {
    -
    6694  Normal,
    -
    6695  // Used by "Linear" algorithm.
    -
    6696  UpperAddress,
    -
    6697  EndOf1st,
    -
    6698  EndOf2nd,
    -
    6699 };
    -
    6700 
    -
    6701 /*
    -
    6702 Parameters of planned allocation inside a VmaDeviceMemoryBlock.
    -
    6703 
    -
    6704 If canMakeOtherLost was false:
    -
    6705 - item points to a FREE suballocation.
    -
    6706 - itemsToMakeLostCount is 0.
    -
    6707 
    -
    6708 If canMakeOtherLost was true:
    -
    6709 - item points to first of sequence of suballocations, which are either FREE,
    -
    6710  or point to VmaAllocations that can become lost.
    -
    6711 - itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for
    -
    6712  the requested allocation to succeed.
    -
    6713 */
    -
    6714 struct VmaAllocationRequest
    -
    6715 {
    -
    6716  VkDeviceSize offset;
    -
    6717  VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation.
    -
    6718  VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
    -
    6719  VmaSuballocationList::iterator item;
    -
    6720  size_t itemsToMakeLostCount;
    -
    6721  void* customData;
    -
    6722  VmaAllocationRequestType type;
    -
    6723 
    -
    6724  VkDeviceSize CalcCost() const
    -
    6725  {
    -
    6726  return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST;
    -
    6727  }
    -
    6728 };
    -
    6729 
    -
    6730 /*
    -
    6731 Data structure used for bookkeeping of allocations and unused ranges of memory
    -
    6732 in a single VkDeviceMemory block.
    -
    6733 */
    -
    6734 class VmaBlockMetadata
    -
    6735 {
    -
    6736 public:
    -
    6737  VmaBlockMetadata(VmaAllocator hAllocator);
    -
    6738  virtual ~VmaBlockMetadata() { }
    -
    6739  virtual void Init(VkDeviceSize size) { m_Size = size; }
    -
    6740 
    -
    6741  // Validates all data structures inside this object. If not valid, returns false.
    -
    6742  virtual bool Validate() const = 0;
    -
    6743  VkDeviceSize GetSize() const { return m_Size; }
    -
    6744  virtual size_t GetAllocationCount() const = 0;
    -
    6745  virtual VkDeviceSize GetSumFreeSize() const = 0;
    -
    6746  virtual VkDeviceSize GetUnusedRangeSizeMax() const = 0;
    -
    6747  // Returns true if this block is empty - contains only single free suballocation.
    -
    6748  virtual bool IsEmpty() const = 0;
    -
    6749 
    -
    6750  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const = 0;
    -
    6751  // Shouldn't modify blockCount.
    -
    6752  virtual void AddPoolStats(VmaPoolStats& inoutStats) const = 0;
    -
    6753 
    -
    6754 #if VMA_STATS_STRING_ENABLED
    -
    6755  virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0;
    -
    6756 #endif
    -
    6757 
    -
    6758  // Tries to find a place for suballocation with given parameters inside this block.
    -
    6759  // If succeeded, fills pAllocationRequest and returns true.
    -
    6760  // If failed, returns false.
    -
    6761  virtual bool CreateAllocationRequest(
    -
    6762  uint32_t currentFrameIndex,
    -
    6763  uint32_t frameInUseCount,
    -
    6764  VkDeviceSize bufferImageGranularity,
    -
    6765  VkDeviceSize allocSize,
    -
    6766  VkDeviceSize allocAlignment,
    -
    6767  bool upperAddress,
    -
    6768  VmaSuballocationType allocType,
    -
    6769  bool canMakeOtherLost,
    -
    6770  // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags.
    -
    6771  uint32_t strategy,
    -
    6772  VmaAllocationRequest* pAllocationRequest) = 0;
    -
    6773 
    -
    6774  virtual bool MakeRequestedAllocationsLost(
    -
    6775  uint32_t currentFrameIndex,
    -
    6776  uint32_t frameInUseCount,
    -
    6777  VmaAllocationRequest* pAllocationRequest) = 0;
    -
    6778 
    -
    6779  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) = 0;
    -
    6780 
    -
    6781  virtual VkResult CheckCorruption(const void* pBlockData) = 0;
    -
    6782 
    -
    6783  // Makes actual allocation based on request. Request must already be checked and valid.
    -
    6784  virtual void Alloc(
    -
    6785  const VmaAllocationRequest& request,
    -
    6786  VmaSuballocationType type,
    -
    6787  VkDeviceSize allocSize,
    -
    6788  VmaAllocation hAllocation) = 0;
    -
    6789 
    -
    6790  // Frees suballocation assigned to given memory region.
    -
    6791  virtual void Free(const VmaAllocation allocation) = 0;
    -
    6792  virtual void FreeAtOffset(VkDeviceSize offset) = 0;
    +
    6632  union
    +
    6633  {
    +
    6634  // Allocation out of VmaDeviceMemoryBlock.
    +
    6635  BlockAllocation m_BlockAllocation;
    +
    6636  // Allocation for an object that has its own private VkDeviceMemory.
    +
    6637  DedicatedAllocation m_DedicatedAllocation;
    +
    6638  };
    +
    6639 
    +
    6640 #if VMA_STATS_STRING_ENABLED
    +
    6641  uint32_t m_CreationFrameIndex;
    +
    6642  uint32_t m_BufferImageUsage; // 0 if unknown.
    +
    6643 #endif
    +
    6644 
    +
    6645  void FreeUserDataString(VmaAllocator hAllocator);
    +
    6646 
    +
    6647  friend struct VmaDedicatedAllocationListItemTraits;
    +
    6648 };
    +
    6649 
    +
    6650 struct VmaDedicatedAllocationListItemTraits
    +
    6651 {
    +
    6652  typedef VmaAllocation_T ItemType;
    +
    6653  static ItemType* GetPrev(const ItemType* item)
    +
    6654  {
    +
    6655  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    +
    6656  return item->m_DedicatedAllocation.m_Prev;
    +
    6657  }
    +
    6658  static ItemType* GetNext(const ItemType* item)
    +
    6659  {
    +
    6660  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    +
    6661  return item->m_DedicatedAllocation.m_Next;
    +
    6662  }
    +
    6663  static ItemType*& AccessPrev(ItemType* item)
    +
    6664  {
    +
    6665  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    +
    6666  return item->m_DedicatedAllocation.m_Prev;
    +
    6667  }
    +
    6668  static ItemType*& AccessNext(ItemType* item){
    +
    6669  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    +
    6670  return item->m_DedicatedAllocation.m_Next;
    +
    6671  }
    +
    6672 };
    +
    6673 
    +
    6674 /*
    +
    6675 Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as
    +
    6676 allocated memory block or free.
    +
    6677 */
    +
    6678 struct VmaSuballocation
    +
    6679 {
    +
    6680  VkDeviceSize offset;
    +
    6681  VkDeviceSize size;
    +
    6682  VmaAllocation hAllocation;
    +
    6683  VmaSuballocationType type;
    +
    6684 };
    +
    6685 
    +
    6686 // Comparator for offsets.
    +
    6687 struct VmaSuballocationOffsetLess
    +
    6688 {
    +
    6689  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
    +
    6690  {
    +
    6691  return lhs.offset < rhs.offset;
    +
    6692  }
    +
    6693 };
    +
    6694 struct VmaSuballocationOffsetGreater
    +
    6695 {
    +
    6696  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
    +
    6697  {
    +
    6698  return lhs.offset > rhs.offset;
    +
    6699  }
    +
    6700 };
    +
    6701 
    +
    6702 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
    +
    6703 
    +
    6704 // Cost of one additional allocation lost, as equivalent in bytes.
    +
    6705 static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576;
    +
    6706 
    +
    6707 enum class VmaAllocationRequestType
    +
    6708 {
    +
    6709  Normal,
    +
    6710  // Used by "Linear" algorithm.
    +
    6711  UpperAddress,
    +
    6712  EndOf1st,
    +
    6713  EndOf2nd,
    +
    6714 };
    +
    6715 
    +
    6716 /*
    +
    6717 Parameters of planned allocation inside a VmaDeviceMemoryBlock.
    +
    6718 
    +
    6719 If canMakeOtherLost was false:
    +
    6720 - item points to a FREE suballocation.
    +
    6721 - itemsToMakeLostCount is 0.
    +
    6722 
    +
    6723 If canMakeOtherLost was true:
    +
    6724 - item points to first of sequence of suballocations, which are either FREE,
    +
    6725  or point to VmaAllocations that can become lost.
    +
    6726 - itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for
    +
    6727  the requested allocation to succeed.
    +
    6728 */
    +
    6729 struct VmaAllocationRequest
    +
    6730 {
    +
    6731  VkDeviceSize offset;
    +
    6732  VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation.
    +
    6733  VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
    +
    6734  VmaSuballocationList::iterator item;
    +
    6735  size_t itemsToMakeLostCount;
    +
    6736  void* customData;
    +
    6737  VmaAllocationRequestType type;
    +
    6738 
    +
    6739  VkDeviceSize CalcCost() const
    +
    6740  {
    +
    6741  return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST;
    +
    6742  }
    +
    6743 };
    +
    6744 
    +
    6745 /*
    +
    6746 Data structure used for bookkeeping of allocations and unused ranges of memory
    +
    6747 in a single VkDeviceMemory block.
    +
    6748 */
    +
    6749 class VmaBlockMetadata
    +
    6750 {
    +
    6751 public:
    +
    6752  VmaBlockMetadata(VmaAllocator hAllocator);
    +
    6753  virtual ~VmaBlockMetadata() { }
    +
    6754  virtual void Init(VkDeviceSize size) { m_Size = size; }
    +
    6755 
    +
    6756  // Validates all data structures inside this object. If not valid, returns false.
    +
    6757  virtual bool Validate() const = 0;
    +
    6758  VkDeviceSize GetSize() const { return m_Size; }
    +
    6759  virtual size_t GetAllocationCount() const = 0;
    +
    6760  virtual VkDeviceSize GetSumFreeSize() const = 0;
    +
    6761  virtual VkDeviceSize GetUnusedRangeSizeMax() const = 0;
    +
    6762  // Returns true if this block is empty - contains only single free suballocation.
    +
    6763  virtual bool IsEmpty() const = 0;
    +
    6764 
    +
    6765  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const = 0;
    +
    6766  // Shouldn't modify blockCount.
    +
    6767  virtual void AddPoolStats(VmaPoolStats& inoutStats) const = 0;
    +
    6768 
    +
    6769 #if VMA_STATS_STRING_ENABLED
    +
    6770  virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0;
    +
    6771 #endif
    +
    6772 
    +
    6773  // Tries to find a place for suballocation with given parameters inside this block.
    +
    6774  // If succeeded, fills pAllocationRequest and returns true.
    +
    6775  // If failed, returns false.
    +
    6776  virtual bool CreateAllocationRequest(
    +
    6777  uint32_t currentFrameIndex,
    +
    6778  uint32_t frameInUseCount,
    +
    6779  VkDeviceSize bufferImageGranularity,
    +
    6780  VkDeviceSize allocSize,
    +
    6781  VkDeviceSize allocAlignment,
    +
    6782  bool upperAddress,
    +
    6783  VmaSuballocationType allocType,
    +
    6784  bool canMakeOtherLost,
    +
    6785  // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags.
    +
    6786  uint32_t strategy,
    +
    6787  VmaAllocationRequest* pAllocationRequest) = 0;
    +
    6788 
    +
    6789  virtual bool MakeRequestedAllocationsLost(
    +
    6790  uint32_t currentFrameIndex,
    +
    6791  uint32_t frameInUseCount,
    +
    6792  VmaAllocationRequest* pAllocationRequest) = 0;
    6793 
    -
    6794 protected:
    -
    6795  const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
    -
    6796 
    -
    6797 #if VMA_STATS_STRING_ENABLED
    -
    6798  void PrintDetailedMap_Begin(class VmaJsonWriter& json,
    -
    6799  VkDeviceSize unusedBytes,
    -
    6800  size_t allocationCount,
    -
    6801  size_t unusedRangeCount) const;
    -
    6802  void PrintDetailedMap_Allocation(class VmaJsonWriter& json,
    -
    6803  VkDeviceSize offset,
    -
    6804  VmaAllocation hAllocation) const;
    -
    6805  void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
    -
    6806  VkDeviceSize offset,
    -
    6807  VkDeviceSize size) const;
    -
    6808  void PrintDetailedMap_End(class VmaJsonWriter& json) const;
    -
    6809 #endif
    -
    6810 
    -
    6811 private:
    -
    6812  VkDeviceSize m_Size;
    -
    6813  const VkAllocationCallbacks* m_pAllocationCallbacks;
    -
    6814 };
    -
    6815 
    -
    6816 #define VMA_VALIDATE(cond) do { if(!(cond)) { \
    -
    6817  VMA_ASSERT(0 && "Validation failed: " #cond); \
    -
    6818  return false; \
    -
    6819  } } while(false)
    -
    6820 
    -
    6821 class VmaBlockMetadata_Generic : public VmaBlockMetadata
    -
    6822 {
    -
    6823  VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic)
    -
    6824 public:
    -
    6825  VmaBlockMetadata_Generic(VmaAllocator hAllocator);
    -
    6826  virtual ~VmaBlockMetadata_Generic();
    -
    6827  virtual void Init(VkDeviceSize size);
    -
    6828 
    -
    6829  virtual bool Validate() const;
    -
    6830  virtual size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; }
    -
    6831  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
    -
    6832  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
    -
    6833  virtual bool IsEmpty() const;
    -
    6834 
    -
    6835  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
    -
    6836  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
    -
    6837 
    -
    6838 #if VMA_STATS_STRING_ENABLED
    -
    6839  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
    -
    6840 #endif
    -
    6841 
    -
    6842  virtual bool CreateAllocationRequest(
    -
    6843  uint32_t currentFrameIndex,
    -
    6844  uint32_t frameInUseCount,
    -
    6845  VkDeviceSize bufferImageGranularity,
    -
    6846  VkDeviceSize allocSize,
    -
    6847  VkDeviceSize allocAlignment,
    -
    6848  bool upperAddress,
    -
    6849  VmaSuballocationType allocType,
    -
    6850  bool canMakeOtherLost,
    -
    6851  uint32_t strategy,
    -
    6852  VmaAllocationRequest* pAllocationRequest);
    -
    6853 
    -
    6854  virtual bool MakeRequestedAllocationsLost(
    -
    6855  uint32_t currentFrameIndex,
    -
    6856  uint32_t frameInUseCount,
    -
    6857  VmaAllocationRequest* pAllocationRequest);
    -
    6858 
    -
    6859  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    -
    6860 
    -
    6861  virtual VkResult CheckCorruption(const void* pBlockData);
    -
    6862 
    -
    6863  virtual void Alloc(
    -
    6864  const VmaAllocationRequest& request,
    -
    6865  VmaSuballocationType type,
    -
    6866  VkDeviceSize allocSize,
    -
    6867  VmaAllocation hAllocation);
    +
    6794  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) = 0;
    +
    6795 
    +
    6796  virtual VkResult CheckCorruption(const void* pBlockData) = 0;
    +
    6797 
    +
    6798  // Makes actual allocation based on request. Request must already be checked and valid.
    +
    6799  virtual void Alloc(
    +
    6800  const VmaAllocationRequest& request,
    +
    6801  VmaSuballocationType type,
    +
    6802  VkDeviceSize allocSize,
    +
    6803  VmaAllocation hAllocation) = 0;
    +
    6804 
    +
    6805  // Frees suballocation assigned to given memory region.
    +
    6806  virtual void Free(const VmaAllocation allocation) = 0;
    +
    6807  virtual void FreeAtOffset(VkDeviceSize offset) = 0;
    +
    6808 
    +
    6809 protected:
    +
    6810  const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
    +
    6811 
    +
    6812 #if VMA_STATS_STRING_ENABLED
    +
    6813  void PrintDetailedMap_Begin(class VmaJsonWriter& json,
    +
    6814  VkDeviceSize unusedBytes,
    +
    6815  size_t allocationCount,
    +
    6816  size_t unusedRangeCount) const;
    +
    6817  void PrintDetailedMap_Allocation(class VmaJsonWriter& json,
    +
    6818  VkDeviceSize offset,
    +
    6819  VmaAllocation hAllocation) const;
    +
    6820  void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
    +
    6821  VkDeviceSize offset,
    +
    6822  VkDeviceSize size) const;
    +
    6823  void PrintDetailedMap_End(class VmaJsonWriter& json) const;
    +
    6824 #endif
    +
    6825 
    +
    6826 private:
    +
    6827  VkDeviceSize m_Size;
    +
    6828  const VkAllocationCallbacks* m_pAllocationCallbacks;
    +
    6829 };
    +
    6830 
    +
    6831 #define VMA_VALIDATE(cond) do { if(!(cond)) { \
    +
    6832  VMA_ASSERT(0 && "Validation failed: " #cond); \
    +
    6833  return false; \
    +
    6834  } } while(false)
    +
    6835 
    +
    6836 class VmaBlockMetadata_Generic : public VmaBlockMetadata
    +
    6837 {
    +
    6838  VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic)
    +
    6839 public:
    +
    6840  VmaBlockMetadata_Generic(VmaAllocator hAllocator);
    +
    6841  virtual ~VmaBlockMetadata_Generic();
    +
    6842  virtual void Init(VkDeviceSize size);
    +
    6843 
    +
    6844  virtual bool Validate() const;
    +
    6845  virtual size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; }
    +
    6846  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
    +
    6847  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
    +
    6848  virtual bool IsEmpty() const;
    +
    6849 
    +
    6850  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
    +
    6851  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
    +
    6852 
    +
    6853 #if VMA_STATS_STRING_ENABLED
    +
    6854  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
    +
    6855 #endif
    +
    6856 
    +
    6857  virtual bool CreateAllocationRequest(
    +
    6858  uint32_t currentFrameIndex,
    +
    6859  uint32_t frameInUseCount,
    +
    6860  VkDeviceSize bufferImageGranularity,
    +
    6861  VkDeviceSize allocSize,
    +
    6862  VkDeviceSize allocAlignment,
    +
    6863  bool upperAddress,
    +
    6864  VmaSuballocationType allocType,
    +
    6865  bool canMakeOtherLost,
    +
    6866  uint32_t strategy,
    +
    6867  VmaAllocationRequest* pAllocationRequest);
    6868 
    -
    6869  virtual void Free(const VmaAllocation allocation);
    -
    6870  virtual void FreeAtOffset(VkDeviceSize offset);
    -
    6871 
    -
    6873  // For defragmentation
    -
    6874 
    -
    6875  bool IsBufferImageGranularityConflictPossible(
    -
    6876  VkDeviceSize bufferImageGranularity,
    -
    6877  VmaSuballocationType& inOutPrevSuballocType) const;
    -
    6878 
    -
    6879 private:
    -
    6880  friend class VmaDefragmentationAlgorithm_Generic;
    -
    6881  friend class VmaDefragmentationAlgorithm_Fast;
    -
    6882 
    -
    6883  uint32_t m_FreeCount;
    -
    6884  VkDeviceSize m_SumFreeSize;
    -
    6885  VmaSuballocationList m_Suballocations;
    -
    6886  // Suballocations that are free and have size greater than certain threshold.
    -
    6887  // Sorted by size, ascending.
    -
    6888  VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
    +
    6869  virtual bool MakeRequestedAllocationsLost(
    +
    6870  uint32_t currentFrameIndex,
    +
    6871  uint32_t frameInUseCount,
    +
    6872  VmaAllocationRequest* pAllocationRequest);
    +
    6873 
    +
    6874  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    +
    6875 
    +
    6876  virtual VkResult CheckCorruption(const void* pBlockData);
    +
    6877 
    +
    6878  virtual void Alloc(
    +
    6879  const VmaAllocationRequest& request,
    +
    6880  VmaSuballocationType type,
    +
    6881  VkDeviceSize allocSize,
    +
    6882  VmaAllocation hAllocation);
    +
    6883 
    +
    6884  virtual void Free(const VmaAllocation allocation);
    +
    6885  virtual void FreeAtOffset(VkDeviceSize offset);
    +
    6886 
    +
    6888  // For defragmentation
    6889 
    -
    6890  bool ValidateFreeSuballocationList() const;
    -
    6891 
    -
    6892  // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
    -
    6893  // If yes, fills pOffset and returns true. If no, returns false.
    -
    6894  bool CheckAllocation(
    -
    6895  uint32_t currentFrameIndex,
    -
    6896  uint32_t frameInUseCount,
    -
    6897  VkDeviceSize bufferImageGranularity,
    -
    6898  VkDeviceSize allocSize,
    -
    6899  VkDeviceSize allocAlignment,
    -
    6900  VmaSuballocationType allocType,
    -
    6901  VmaSuballocationList::const_iterator suballocItem,
    -
    6902  bool canMakeOtherLost,
    -
    6903  VkDeviceSize* pOffset,
    -
    6904  size_t* itemsToMakeLostCount,
    -
    6905  VkDeviceSize* pSumFreeSize,
    -
    6906  VkDeviceSize* pSumItemSize) const;
    -
    6907  // Given free suballocation, it merges it with following one, which must also be free.
    -
    6908  void MergeFreeWithNext(VmaSuballocationList::iterator item);
    -
    6909  // Releases given suballocation, making it free.
    -
    6910  // Merges it with adjacent free suballocations if applicable.
    -
    6911  // Returns iterator to new free suballocation at this place.
    -
    6912  VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem);
    -
    6913  // Given free suballocation, it inserts it into sorted list of
    -
    6914  // m_FreeSuballocationsBySize if it's suitable.
    -
    6915  void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
    -
    6916  // Given free suballocation, it removes it from sorted list of
    -
    6917  // m_FreeSuballocationsBySize if it's suitable.
    -
    6918  void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
    -
    6919 };
    -
    6920 
    -
    6921 /*
    -
    6922 Allocations and their references in internal data structure look like this:
    -
    6923 
    -
    6924 if(m_2ndVectorMode == SECOND_VECTOR_EMPTY):
    -
    6925 
    -
    6926  0 +-------+
    -
    6927  | |
    -
    6928  | |
    -
    6929  | |
    -
    6930  +-------+
    -
    6931  | Alloc | 1st[m_1stNullItemsBeginCount]
    -
    6932  +-------+
    -
    6933  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
    -
    6934  +-------+
    -
    6935  | ... |
    -
    6936  +-------+
    -
    6937  | Alloc | 1st[1st.size() - 1]
    -
    6938  +-------+
    -
    6939  | |
    -
    6940  | |
    -
    6941  | |
    -
    6942 GetSize() +-------+
    -
    6943 
    -
    6944 if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER):
    -
    6945 
    -
    6946  0 +-------+
    -
    6947  | Alloc | 2nd[0]
    -
    6948  +-------+
    -
    6949  | Alloc | 2nd[1]
    -
    6950  +-------+
    -
    6951  | ... |
    -
    6952  +-------+
    -
    6953  | Alloc | 2nd[2nd.size() - 1]
    -
    6954  +-------+
    +
    6890  bool IsBufferImageGranularityConflictPossible(
    +
    6891  VkDeviceSize bufferImageGranularity,
    +
    6892  VmaSuballocationType& inOutPrevSuballocType) const;
    +
    6893 
    +
    6894 private:
    +
    6895  friend class VmaDefragmentationAlgorithm_Generic;
    +
    6896  friend class VmaDefragmentationAlgorithm_Fast;
    +
    6897 
    +
    6898  uint32_t m_FreeCount;
    +
    6899  VkDeviceSize m_SumFreeSize;
    +
    6900  VmaSuballocationList m_Suballocations;
    +
    6901  // Suballocations that are free and have size greater than certain threshold.
    +
    6902  // Sorted by size, ascending.
    +
    6903  VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
    +
    6904 
    +
    6905  bool ValidateFreeSuballocationList() const;
    +
    6906 
    +
    6907  // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
    +
    6908  // If yes, fills pOffset and returns true. If no, returns false.
    +
    6909  bool CheckAllocation(
    +
    6910  uint32_t currentFrameIndex,
    +
    6911  uint32_t frameInUseCount,
    +
    6912  VkDeviceSize bufferImageGranularity,
    +
    6913  VkDeviceSize allocSize,
    +
    6914  VkDeviceSize allocAlignment,
    +
    6915  VmaSuballocationType allocType,
    +
    6916  VmaSuballocationList::const_iterator suballocItem,
    +
    6917  bool canMakeOtherLost,
    +
    6918  VkDeviceSize* pOffset,
    +
    6919  size_t* itemsToMakeLostCount,
    +
    6920  VkDeviceSize* pSumFreeSize,
    +
    6921  VkDeviceSize* pSumItemSize) const;
    +
    6922  // Given free suballocation, it merges it with following one, which must also be free.
    +
    6923  void MergeFreeWithNext(VmaSuballocationList::iterator item);
    +
    6924  // Releases given suballocation, making it free.
    +
    6925  // Merges it with adjacent free suballocations if applicable.
    +
    6926  // Returns iterator to new free suballocation at this place.
    +
    6927  VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem);
    +
    6928  // Given free suballocation, it inserts it into sorted list of
    +
    6929  // m_FreeSuballocationsBySize if it's suitable.
    +
    6930  void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
    +
    6931  // Given free suballocation, it removes it from sorted list of
    +
    6932  // m_FreeSuballocationsBySize if it's suitable.
    +
    6933  void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
    +
    6934 };
    +
    6935 
    +
    6936 /*
    +
    6937 Allocations and their references in internal data structure look like this:
    +
    6938 
    +
    6939 if(m_2ndVectorMode == SECOND_VECTOR_EMPTY):
    +
    6940 
    +
    6941  0 +-------+
    +
    6942  | |
    +
    6943  | |
    +
    6944  | |
    +
    6945  +-------+
    +
    6946  | Alloc | 1st[m_1stNullItemsBeginCount]
    +
    6947  +-------+
    +
    6948  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
    +
    6949  +-------+
    +
    6950  | ... |
    +
    6951  +-------+
    +
    6952  | Alloc | 1st[1st.size() - 1]
    +
    6953  +-------+
    +
    6954  | |
    6955  | |
    6956  | |
    -
    6957  | |
    -
    6958  +-------+
    -
    6959  | Alloc | 1st[m_1stNullItemsBeginCount]
    -
    6960  +-------+
    -
    6961  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
    -
    6962  +-------+
    -
    6963  | ... |
    -
    6964  +-------+
    -
    6965  | Alloc | 1st[1st.size() - 1]
    -
    6966  +-------+
    -
    6967  | |
    -
    6968 GetSize() +-------+
    -
    6969 
    -
    6970 if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK):
    -
    6971 
    -
    6972  0 +-------+
    -
    6973  | |
    -
    6974  | |
    -
    6975  | |
    -
    6976  +-------+
    -
    6977  | Alloc | 1st[m_1stNullItemsBeginCount]
    -
    6978  +-------+
    -
    6979  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
    -
    6980  +-------+
    -
    6981  | ... |
    -
    6982  +-------+
    -
    6983  | Alloc | 1st[1st.size() - 1]
    -
    6984  +-------+
    -
    6985  | |
    -
    6986  | |
    -
    6987  | |
    -
    6988  +-------+
    -
    6989  | Alloc | 2nd[2nd.size() - 1]
    -
    6990  +-------+
    -
    6991  | ... |
    -
    6992  +-------+
    -
    6993  | Alloc | 2nd[1]
    -
    6994  +-------+
    -
    6995  | Alloc | 2nd[0]
    -
    6996 GetSize() +-------+
    -
    6997 
    -
    6998 */
    -
    6999 class VmaBlockMetadata_Linear : public VmaBlockMetadata
    -
    7000 {
    -
    7001  VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear)
    -
    7002 public:
    -
    7003  VmaBlockMetadata_Linear(VmaAllocator hAllocator);
    -
    7004  virtual ~VmaBlockMetadata_Linear();
    -
    7005  virtual void Init(VkDeviceSize size);
    -
    7006 
    -
    7007  virtual bool Validate() const;
    -
    7008  virtual size_t GetAllocationCount() const;
    -
    7009  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
    -
    7010  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
    -
    7011  virtual bool IsEmpty() const { return GetAllocationCount() == 0; }
    -
    7012 
    -
    7013  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
    -
    7014  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
    -
    7015 
    -
    7016 #if VMA_STATS_STRING_ENABLED
    -
    7017  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
    -
    7018 #endif
    -
    7019 
    -
    7020  virtual bool CreateAllocationRequest(
    -
    7021  uint32_t currentFrameIndex,
    -
    7022  uint32_t frameInUseCount,
    -
    7023  VkDeviceSize bufferImageGranularity,
    -
    7024  VkDeviceSize allocSize,
    -
    7025  VkDeviceSize allocAlignment,
    -
    7026  bool upperAddress,
    -
    7027  VmaSuballocationType allocType,
    -
    7028  bool canMakeOtherLost,
    -
    7029  uint32_t strategy,
    -
    7030  VmaAllocationRequest* pAllocationRequest);
    -
    7031 
    -
    7032  virtual bool MakeRequestedAllocationsLost(
    -
    7033  uint32_t currentFrameIndex,
    -
    7034  uint32_t frameInUseCount,
    -
    7035  VmaAllocationRequest* pAllocationRequest);
    -
    7036 
    -
    7037  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    -
    7038 
    -
    7039  virtual VkResult CheckCorruption(const void* pBlockData);
    -
    7040 
    -
    7041  virtual void Alloc(
    -
    7042  const VmaAllocationRequest& request,
    -
    7043  VmaSuballocationType type,
    -
    7044  VkDeviceSize allocSize,
    -
    7045  VmaAllocation hAllocation);
    +
    6957 GetSize() +-------+
    +
    6958 
    +
    6959 if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER):
    +
    6960 
    +
    6961  0 +-------+
    +
    6962  | Alloc | 2nd[0]
    +
    6963  +-------+
    +
    6964  | Alloc | 2nd[1]
    +
    6965  +-------+
    +
    6966  | ... |
    +
    6967  +-------+
    +
    6968  | Alloc | 2nd[2nd.size() - 1]
    +
    6969  +-------+
    +
    6970  | |
    +
    6971  | |
    +
    6972  | |
    +
    6973  +-------+
    +
    6974  | Alloc | 1st[m_1stNullItemsBeginCount]
    +
    6975  +-------+
    +
    6976  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
    +
    6977  +-------+
    +
    6978  | ... |
    +
    6979  +-------+
    +
    6980  | Alloc | 1st[1st.size() - 1]
    +
    6981  +-------+
    +
    6982  | |
    +
    6983 GetSize() +-------+
    +
    6984 
    +
    6985 if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK):
    +
    6986 
    +
    6987  0 +-------+
    +
    6988  | |
    +
    6989  | |
    +
    6990  | |
    +
    6991  +-------+
    +
    6992  | Alloc | 1st[m_1stNullItemsBeginCount]
    +
    6993  +-------+
    +
    6994  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
    +
    6995  +-------+
    +
    6996  | ... |
    +
    6997  +-------+
    +
    6998  | Alloc | 1st[1st.size() - 1]
    +
    6999  +-------+
    +
    7000  | |
    +
    7001  | |
    +
    7002  | |
    +
    7003  +-------+
    +
    7004  | Alloc | 2nd[2nd.size() - 1]
    +
    7005  +-------+
    +
    7006  | ... |
    +
    7007  +-------+
    +
    7008  | Alloc | 2nd[1]
    +
    7009  +-------+
    +
    7010  | Alloc | 2nd[0]
    +
    7011 GetSize() +-------+
    +
    7012 
    +
    7013 */
    +
    7014 class VmaBlockMetadata_Linear : public VmaBlockMetadata
    +
    7015 {
    +
    7016  VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear)
    +
    7017 public:
    +
    7018  VmaBlockMetadata_Linear(VmaAllocator hAllocator);
    +
    7019  virtual ~VmaBlockMetadata_Linear();
    +
    7020  virtual void Init(VkDeviceSize size);
    +
    7021 
    +
    7022  virtual bool Validate() const;
    +
    7023  virtual size_t GetAllocationCount() const;
    +
    7024  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
    +
    7025  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
    +
    7026  virtual bool IsEmpty() const { return GetAllocationCount() == 0; }
    +
    7027 
    +
    7028  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
    +
    7029  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
    +
    7030 
    +
    7031 #if VMA_STATS_STRING_ENABLED
    +
    7032  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
    +
    7033 #endif
    +
    7034 
    +
    7035  virtual bool CreateAllocationRequest(
    +
    7036  uint32_t currentFrameIndex,
    +
    7037  uint32_t frameInUseCount,
    +
    7038  VkDeviceSize bufferImageGranularity,
    +
    7039  VkDeviceSize allocSize,
    +
    7040  VkDeviceSize allocAlignment,
    +
    7041  bool upperAddress,
    +
    7042  VmaSuballocationType allocType,
    +
    7043  bool canMakeOtherLost,
    +
    7044  uint32_t strategy,
    +
    7045  VmaAllocationRequest* pAllocationRequest);
    7046 
    -
    7047  virtual void Free(const VmaAllocation allocation);
    -
    7048  virtual void FreeAtOffset(VkDeviceSize offset);
    -
    7049 
    -
    7050 private:
    -
    7051  /*
    -
    7052  There are two suballocation vectors, used in ping-pong way.
    -
    7053  The one with index m_1stVectorIndex is called 1st.
    -
    7054  The one with index (m_1stVectorIndex ^ 1) is called 2nd.
    -
    7055  2nd can be non-empty only when 1st is not empty.
    -
    7056  When 2nd is not empty, m_2ndVectorMode indicates its mode of operation.
    -
    7057  */
    -
    7058  typedef VmaVector< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > SuballocationVectorType;
    -
    7059 
    -
    7060  enum SECOND_VECTOR_MODE
    -
    7061  {
    -
    7062  SECOND_VECTOR_EMPTY,
    -
    7063  /*
    -
    7064  Suballocations in 2nd vector are created later than the ones in 1st, but they
    -
    7065  all have smaller offset.
    -
    7066  */
    -
    7067  SECOND_VECTOR_RING_BUFFER,
    -
    7068  /*
    -
    7069  Suballocations in 2nd vector are upper side of double stack.
    -
    7070  They all have offsets higher than those in 1st vector.
    -
    7071  Top of this stack means smaller offsets, but higher indices in this vector.
    -
    7072  */
    -
    7073  SECOND_VECTOR_DOUBLE_STACK,
    -
    7074  };
    -
    7075 
    -
    7076  VkDeviceSize m_SumFreeSize;
    -
    7077  SuballocationVectorType m_Suballocations0, m_Suballocations1;
    -
    7078  uint32_t m_1stVectorIndex;
    -
    7079  SECOND_VECTOR_MODE m_2ndVectorMode;
    -
    7080 
    -
    7081  SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
    -
    7082  SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
    -
    7083  const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
    -
    7084  const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
    -
    7085 
    -
    7086  // Number of items in 1st vector with hAllocation = null at the beginning.
    -
    7087  size_t m_1stNullItemsBeginCount;
    -
    7088  // Number of other items in 1st vector with hAllocation = null somewhere in the middle.
    -
    7089  size_t m_1stNullItemsMiddleCount;
    -
    7090  // Number of items in 2nd vector with hAllocation = null.
    -
    7091  size_t m_2ndNullItemsCount;
    -
    7092 
    -
    7093  bool ShouldCompact1st() const;
    -
    7094  void CleanupAfterFree();
    +
    7047  virtual bool MakeRequestedAllocationsLost(
    +
    7048  uint32_t currentFrameIndex,
    +
    7049  uint32_t frameInUseCount,
    +
    7050  VmaAllocationRequest* pAllocationRequest);
    +
    7051 
    +
    7052  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    +
    7053 
    +
    7054  virtual VkResult CheckCorruption(const void* pBlockData);
    +
    7055 
    +
    7056  virtual void Alloc(
    +
    7057  const VmaAllocationRequest& request,
    +
    7058  VmaSuballocationType type,
    +
    7059  VkDeviceSize allocSize,
    +
    7060  VmaAllocation hAllocation);
    +
    7061 
    +
    7062  virtual void Free(const VmaAllocation allocation);
    +
    7063  virtual void FreeAtOffset(VkDeviceSize offset);
    +
    7064 
    +
    7065 private:
    +
    7066  /*
    +
    7067  There are two suballocation vectors, used in ping-pong way.
    +
    7068  The one with index m_1stVectorIndex is called 1st.
    +
    7069  The one with index (m_1stVectorIndex ^ 1) is called 2nd.
    +
    7070  2nd can be non-empty only when 1st is not empty.
    +
    7071  When 2nd is not empty, m_2ndVectorMode indicates its mode of operation.
    +
    7072  */
    +
    7073  typedef VmaVector< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > SuballocationVectorType;
    +
    7074 
    +
    7075  enum SECOND_VECTOR_MODE
    +
    7076  {
    +
    7077  SECOND_VECTOR_EMPTY,
    +
    7078  /*
    +
    7079  Suballocations in 2nd vector are created later than the ones in 1st, but they
    +
    7080  all have smaller offset.
    +
    7081  */
    +
    7082  SECOND_VECTOR_RING_BUFFER,
    +
    7083  /*
    +
    7084  Suballocations in 2nd vector are upper side of double stack.
    +
    7085  They all have offsets higher than those in 1st vector.
    +
    7086  Top of this stack means smaller offsets, but higher indices in this vector.
    +
    7087  */
    +
    7088  SECOND_VECTOR_DOUBLE_STACK,
    +
    7089  };
    +
    7090 
    +
    7091  VkDeviceSize m_SumFreeSize;
    +
    7092  SuballocationVectorType m_Suballocations0, m_Suballocations1;
    +
    7093  uint32_t m_1stVectorIndex;
    +
    7094  SECOND_VECTOR_MODE m_2ndVectorMode;
    7095 
    -
    7096  bool CreateAllocationRequest_LowerAddress(
    -
    7097  uint32_t currentFrameIndex,
    -
    7098  uint32_t frameInUseCount,
    -
    7099  VkDeviceSize bufferImageGranularity,
    -
    7100  VkDeviceSize allocSize,
    -
    7101  VkDeviceSize allocAlignment,
    -
    7102  VmaSuballocationType allocType,
    -
    7103  bool canMakeOtherLost,
    -
    7104  uint32_t strategy,
    -
    7105  VmaAllocationRequest* pAllocationRequest);
    -
    7106  bool CreateAllocationRequest_UpperAddress(
    -
    7107  uint32_t currentFrameIndex,
    -
    7108  uint32_t frameInUseCount,
    -
    7109  VkDeviceSize bufferImageGranularity,
    -
    7110  VkDeviceSize allocSize,
    -
    7111  VkDeviceSize allocAlignment,
    -
    7112  VmaSuballocationType allocType,
    -
    7113  bool canMakeOtherLost,
    -
    7114  uint32_t strategy,
    -
    7115  VmaAllocationRequest* pAllocationRequest);
    -
    7116 };
    -
    7117 
    -
    7118 /*
    -
    7119 - GetSize() is the original size of allocated memory block.
    -
    7120 - m_UsableSize is this size aligned down to a power of two.
    -
    7121  All allocations and calculations happen relative to m_UsableSize.
    -
    7122 - GetUnusableSize() is the difference between them.
    -
    7123  It is reported as separate, unused range, not available for allocations.
    -
    7124 
    -
    7125 Node at level 0 has size = m_UsableSize.
    -
    7126 Each next level contains nodes with size 2 times smaller than current level.
    -
    7127 m_LevelCount is the maximum number of levels to use in the current object.
    -
    7128 */
    -
    7129 class VmaBlockMetadata_Buddy : public VmaBlockMetadata
    -
    7130 {
    -
    7131  VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy)
    -
    7132 public:
    -
    7133  VmaBlockMetadata_Buddy(VmaAllocator hAllocator);
    -
    7134  virtual ~VmaBlockMetadata_Buddy();
    -
    7135  virtual void Init(VkDeviceSize size);
    -
    7136 
    -
    7137  virtual bool Validate() const;
    -
    7138  virtual size_t GetAllocationCount() const { return m_AllocationCount; }
    -
    7139  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize + GetUnusableSize(); }
    -
    7140  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
    -
    7141  virtual bool IsEmpty() const { return m_Root->type == Node::TYPE_FREE; }
    -
    7142 
    -
    7143  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
    -
    7144  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
    -
    7145 
    -
    7146 #if VMA_STATS_STRING_ENABLED
    -
    7147  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
    -
    7148 #endif
    -
    7149 
    -
    7150  virtual bool CreateAllocationRequest(
    -
    7151  uint32_t currentFrameIndex,
    -
    7152  uint32_t frameInUseCount,
    -
    7153  VkDeviceSize bufferImageGranularity,
    -
    7154  VkDeviceSize allocSize,
    -
    7155  VkDeviceSize allocAlignment,
    -
    7156  bool upperAddress,
    -
    7157  VmaSuballocationType allocType,
    -
    7158  bool canMakeOtherLost,
    -
    7159  uint32_t strategy,
    -
    7160  VmaAllocationRequest* pAllocationRequest);
    -
    7161 
    -
    7162  virtual bool MakeRequestedAllocationsLost(
    -
    7163  uint32_t currentFrameIndex,
    -
    7164  uint32_t frameInUseCount,
    -
    7165  VmaAllocationRequest* pAllocationRequest);
    -
    7166 
    -
    7167  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    -
    7168 
    -
    7169  virtual VkResult CheckCorruption(const void* pBlockData) { return VK_ERROR_FEATURE_NOT_PRESENT; }
    -
    7170 
    -
    7171  virtual void Alloc(
    -
    7172  const VmaAllocationRequest& request,
    -
    7173  VmaSuballocationType type,
    -
    7174  VkDeviceSize allocSize,
    -
    7175  VmaAllocation hAllocation);
    +
    7096  SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
    +
    7097  SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
    +
    7098  const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
    +
    7099  const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
    +
    7100 
    +
    7101  // Number of items in 1st vector with hAllocation = null at the beginning.
    +
    7102  size_t m_1stNullItemsBeginCount;
    +
    7103  // Number of other items in 1st vector with hAllocation = null somewhere in the middle.
    +
    7104  size_t m_1stNullItemsMiddleCount;
    +
    7105  // Number of items in 2nd vector with hAllocation = null.
    +
    7106  size_t m_2ndNullItemsCount;
    +
    7107 
    +
    7108  bool ShouldCompact1st() const;
    +
    7109  void CleanupAfterFree();
    +
    7110 
    +
    7111  bool CreateAllocationRequest_LowerAddress(
    +
    7112  uint32_t currentFrameIndex,
    +
    7113  uint32_t frameInUseCount,
    +
    7114  VkDeviceSize bufferImageGranularity,
    +
    7115  VkDeviceSize allocSize,
    +
    7116  VkDeviceSize allocAlignment,
    +
    7117  VmaSuballocationType allocType,
    +
    7118  bool canMakeOtherLost,
    +
    7119  uint32_t strategy,
    +
    7120  VmaAllocationRequest* pAllocationRequest);
    +
    7121  bool CreateAllocationRequest_UpperAddress(
    +
    7122  uint32_t currentFrameIndex,
    +
    7123  uint32_t frameInUseCount,
    +
    7124  VkDeviceSize bufferImageGranularity,
    +
    7125  VkDeviceSize allocSize,
    +
    7126  VkDeviceSize allocAlignment,
    +
    7127  VmaSuballocationType allocType,
    +
    7128  bool canMakeOtherLost,
    +
    7129  uint32_t strategy,
    +
    7130  VmaAllocationRequest* pAllocationRequest);
    +
    7131 };
    +
    7132 
    +
    7133 /*
    +
    7134 - GetSize() is the original size of allocated memory block.
    +
    7135 - m_UsableSize is this size aligned down to a power of two.
    +
    7136  All allocations and calculations happen relative to m_UsableSize.
    +
    7137 - GetUnusableSize() is the difference between them.
    +
    7138  It is reported as separate, unused range, not available for allocations.
    +
    7139 
    +
    7140 Node at level 0 has size = m_UsableSize.
    +
    7141 Each next level contains nodes with size 2 times smaller than current level.
    +
    7142 m_LevelCount is the maximum number of levels to use in the current object.
    +
    7143 */
    +
    7144 class VmaBlockMetadata_Buddy : public VmaBlockMetadata
    +
    7145 {
    +
    7146  VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy)
    +
    7147 public:
    +
    7148  VmaBlockMetadata_Buddy(VmaAllocator hAllocator);
    +
    7149  virtual ~VmaBlockMetadata_Buddy();
    +
    7150  virtual void Init(VkDeviceSize size);
    +
    7151 
    +
    7152  virtual bool Validate() const;
    +
    7153  virtual size_t GetAllocationCount() const { return m_AllocationCount; }
    +
    7154  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize + GetUnusableSize(); }
    +
    7155  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
    +
    7156  virtual bool IsEmpty() const { return m_Root->type == Node::TYPE_FREE; }
    +
    7157 
    +
    7158  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
    +
    7159  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
    +
    7160 
    +
    7161 #if VMA_STATS_STRING_ENABLED
    +
    7162  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
    +
    7163 #endif
    +
    7164 
    +
    7165  virtual bool CreateAllocationRequest(
    +
    7166  uint32_t currentFrameIndex,
    +
    7167  uint32_t frameInUseCount,
    +
    7168  VkDeviceSize bufferImageGranularity,
    +
    7169  VkDeviceSize allocSize,
    +
    7170  VkDeviceSize allocAlignment,
    +
    7171  bool upperAddress,
    +
    7172  VmaSuballocationType allocType,
    +
    7173  bool canMakeOtherLost,
    +
    7174  uint32_t strategy,
    +
    7175  VmaAllocationRequest* pAllocationRequest);
    7176 
    -
    7177  virtual void Free(const VmaAllocation allocation) { FreeAtOffset(allocation, allocation->GetOffset()); }
    -
    7178  virtual void FreeAtOffset(VkDeviceSize offset) { FreeAtOffset(VMA_NULL, offset); }
    -
    7179 
    -
    7180 private:
    -
    7181  static const VkDeviceSize MIN_NODE_SIZE = 32;
    -
    7182  static const size_t MAX_LEVELS = 30;
    +
    7177  virtual bool MakeRequestedAllocationsLost(
    +
    7178  uint32_t currentFrameIndex,
    +
    7179  uint32_t frameInUseCount,
    +
    7180  VmaAllocationRequest* pAllocationRequest);
    +
    7181 
    +
    7182  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
    7183 
    -
    7184  struct ValidationContext
    -
    7185  {
    -
    7186  size_t calculatedAllocationCount;
    -
    7187  size_t calculatedFreeCount;
    -
    7188  VkDeviceSize calculatedSumFreeSize;
    -
    7189 
    -
    7190  ValidationContext() :
    -
    7191  calculatedAllocationCount(0),
    -
    7192  calculatedFreeCount(0),
    -
    7193  calculatedSumFreeSize(0) { }
    -
    7194  };
    -
    7195 
    -
    7196  struct Node
    -
    7197  {
    -
    7198  VkDeviceSize offset;
    -
    7199  enum TYPE
    -
    7200  {
    -
    7201  TYPE_FREE,
    -
    7202  TYPE_ALLOCATION,
    -
    7203  TYPE_SPLIT,
    -
    7204  TYPE_COUNT
    -
    7205  } type;
    -
    7206  Node* parent;
    -
    7207  Node* buddy;
    -
    7208 
    -
    7209  union
    -
    7210  {
    -
    7211  struct
    -
    7212  {
    -
    7213  Node* prev;
    -
    7214  Node* next;
    -
    7215  } free;
    -
    7216  struct
    -
    7217  {
    -
    7218  VmaAllocation alloc;
    -
    7219  } allocation;
    -
    7220  struct
    -
    7221  {
    -
    7222  Node* leftChild;
    -
    7223  } split;
    -
    7224  };
    -
    7225  };
    -
    7226 
    -
    7227  // Size of the memory block aligned down to a power of two.
    -
    7228  VkDeviceSize m_UsableSize;
    -
    7229  uint32_t m_LevelCount;
    -
    7230 
    -
    7231  Node* m_Root;
    -
    7232  struct {
    -
    7233  Node* front;
    -
    7234  Node* back;
    -
    7235  } m_FreeList[MAX_LEVELS];
    -
    7236  // Number of nodes in the tree with type == TYPE_ALLOCATION.
    -
    7237  size_t m_AllocationCount;
    -
    7238  // Number of nodes in the tree with type == TYPE_FREE.
    -
    7239  size_t m_FreeCount;
    -
    7240  // This includes space wasted due to internal fragmentation. Doesn't include unusable size.
    -
    7241  VkDeviceSize m_SumFreeSize;
    -
    7242 
    -
    7243  VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; }
    -
    7244  void DeleteNode(Node* node);
    -
    7245  bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;
    -
    7246  uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const;
    -
    7247  inline VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; }
    -
    7248  // Alloc passed just for validation. Can be null.
    -
    7249  void FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset);
    -
    7250  void CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const;
    -
    7251  // Adds node to the front of FreeList at given level.
    -
    7252  // node->type must be FREE.
    -
    7253  // node->free.prev, next can be undefined.
    -
    7254  void AddToFreeListFront(uint32_t level, Node* node);
    -
    7255  // Removes node from FreeList at given level.
    -
    7256  // node->type must be FREE.
    -
    7257  // node->free.prev, next stay untouched.
    -
    7258  void RemoveFromFreeList(uint32_t level, Node* node);
    -
    7259 
    -
    7260 #if VMA_STATS_STRING_ENABLED
    -
    7261  void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const;
    -
    7262 #endif
    -
    7263 };
    -
    7264 
    -
    7265 /*
    -
    7266 Represents a single block of device memory (`VkDeviceMemory`) with all the
    -
    7267 data about its regions (aka suballocations, #VmaAllocation), assigned and free.
    -
    7268 
    -
    7269 Thread-safety: This class must be externally synchronized.
    -
    7270 */
    -
    7271 class VmaDeviceMemoryBlock
    -
    7272 {
    -
    7273  VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock)
    -
    7274 public:
    -
    7275  VmaBlockMetadata* m_pMetadata;
    -
    7276 
    -
    7277  VmaDeviceMemoryBlock(VmaAllocator hAllocator);
    -
    7278 
    -
    7279  ~VmaDeviceMemoryBlock()
    -
    7280  {
    -
    7281  VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped.");
    -
    7282  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    -
    7283  }
    -
    7284 
    -
    7285  // Always call after construction.
    -
    7286  void Init(
    -
    7287  VmaAllocator hAllocator,
    -
    7288  VmaPool hParentPool,
    -
    7289  uint32_t newMemoryTypeIndex,
    -
    7290  VkDeviceMemory newMemory,
    -
    7291  VkDeviceSize newSize,
    -
    7292  uint32_t id,
    -
    7293  uint32_t algorithm);
    -
    7294  // Always call before destruction.
    -
    7295  void Destroy(VmaAllocator allocator);
    -
    7296 
    -
    7297  VmaPool GetParentPool() const { return m_hParentPool; }
    -
    7298  VkDeviceMemory GetDeviceMemory() const { return m_hMemory; }
    -
    7299  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
    -
    7300  uint32_t GetId() const { return m_Id; }
    -
    7301  void* GetMappedData() const { return m_pMappedData; }
    -
    7302 
    -
    7303  // Validates all data structures inside this object. If not valid, returns false.
    -
    7304  bool Validate() const;
    -
    7305 
    -
    7306  VkResult CheckCorruption(VmaAllocator hAllocator);
    -
    7307 
    -
    7308  // ppData can be null.
    -
    7309  VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData);
    -
    7310  void Unmap(VmaAllocator hAllocator, uint32_t count);
    +
    7184  virtual VkResult CheckCorruption(const void* pBlockData) { return VK_ERROR_FEATURE_NOT_PRESENT; }
    +
    7185 
    +
    7186  virtual void Alloc(
    +
    7187  const VmaAllocationRequest& request,
    +
    7188  VmaSuballocationType type,
    +
    7189  VkDeviceSize allocSize,
    +
    7190  VmaAllocation hAllocation);
    +
    7191 
    +
    7192  virtual void Free(const VmaAllocation allocation) { FreeAtOffset(allocation, allocation->GetOffset()); }
    +
    7193  virtual void FreeAtOffset(VkDeviceSize offset) { FreeAtOffset(VMA_NULL, offset); }
    +
    7194 
    +
    7195 private:
    +
    7196  static const VkDeviceSize MIN_NODE_SIZE = 32;
    +
    7197  static const size_t MAX_LEVELS = 30;
    +
    7198 
    +
    7199  struct ValidationContext
    +
    7200  {
    +
    7201  size_t calculatedAllocationCount;
    +
    7202  size_t calculatedFreeCount;
    +
    7203  VkDeviceSize calculatedSumFreeSize;
    +
    7204 
    +
    7205  ValidationContext() :
    +
    7206  calculatedAllocationCount(0),
    +
    7207  calculatedFreeCount(0),
    +
    7208  calculatedSumFreeSize(0) { }
    +
    7209  };
    +
    7210 
    +
    7211  struct Node
    +
    7212  {
    +
    7213  VkDeviceSize offset;
    +
    7214  enum TYPE
    +
    7215  {
    +
    7216  TYPE_FREE,
    +
    7217  TYPE_ALLOCATION,
    +
    7218  TYPE_SPLIT,
    +
    7219  TYPE_COUNT
    +
    7220  } type;
    +
    7221  Node* parent;
    +
    7222  Node* buddy;
    +
    7223 
    +
    7224  union
    +
    7225  {
    +
    7226  struct
    +
    7227  {
    +
    7228  Node* prev;
    +
    7229  Node* next;
    +
    7230  } free;
    +
    7231  struct
    +
    7232  {
    +
    7233  VmaAllocation alloc;
    +
    7234  } allocation;
    +
    7235  struct
    +
    7236  {
    +
    7237  Node* leftChild;
    +
    7238  } split;
    +
    7239  };
    +
    7240  };
    +
    7241 
    +
    7242  // Size of the memory block aligned down to a power of two.
    +
    7243  VkDeviceSize m_UsableSize;
    +
    7244  uint32_t m_LevelCount;
    +
    7245 
    +
    7246  Node* m_Root;
    +
    7247  struct {
    +
    7248  Node* front;
    +
    7249  Node* back;
    +
    7250  } m_FreeList[MAX_LEVELS];
    +
    7251  // Number of nodes in the tree with type == TYPE_ALLOCATION.
    +
    7252  size_t m_AllocationCount;
    +
    7253  // Number of nodes in the tree with type == TYPE_FREE.
    +
    7254  size_t m_FreeCount;
    +
    7255  // This includes space wasted due to internal fragmentation. Doesn't include unusable size.
    +
    7256  VkDeviceSize m_SumFreeSize;
    +
    7257 
    +
    7258  VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; }
    +
    7259  void DeleteNode(Node* node);
    +
    7260  bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;
    +
    7261  uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const;
    +
    7262  inline VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; }
    +
    7263  // Alloc passed just for validation. Can be null.
    +
    7264  void FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset);
    +
    7265  void CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const;
    +
    7266  // Adds node to the front of FreeList at given level.
    +
    7267  // node->type must be FREE.
    +
    7268  // node->free.prev, next can be undefined.
    +
    7269  void AddToFreeListFront(uint32_t level, Node* node);
    +
    7270  // Removes node from FreeList at given level.
    +
    7271  // node->type must be FREE.
    +
    7272  // node->free.prev, next stay untouched.
    +
    7273  void RemoveFromFreeList(uint32_t level, Node* node);
    +
    7274 
    +
    7275 #if VMA_STATS_STRING_ENABLED
    +
    7276  void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const;
    +
    7277 #endif
    +
    7278 };
    +
    7279 
    +
    7280 /*
    +
    7281 Represents a single block of device memory (`VkDeviceMemory`) with all the
    +
    7282 data about its regions (aka suballocations, #VmaAllocation), assigned and free.
    +
    7283 
    +
    7284 Thread-safety: This class must be externally synchronized.
    +
    7285 */
    +
    7286 class VmaDeviceMemoryBlock
    +
    7287 {
    +
    7288  VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock)
    +
    7289 public:
    +
    7290  VmaBlockMetadata* m_pMetadata;
    +
    7291 
    +
    7292  VmaDeviceMemoryBlock(VmaAllocator hAllocator);
    +
    7293 
    +
    7294  ~VmaDeviceMemoryBlock()
    +
    7295  {
    +
    7296  VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped.");
    +
    7297  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    +
    7298  }
    +
    7299 
    +
    7300  // Always call after construction.
    +
    7301  void Init(
    +
    7302  VmaAllocator hAllocator,
    +
    7303  VmaPool hParentPool,
    +
    7304  uint32_t newMemoryTypeIndex,
    +
    7305  VkDeviceMemory newMemory,
    +
    7306  VkDeviceSize newSize,
    +
    7307  uint32_t id,
    +
    7308  uint32_t algorithm);
    +
    7309  // Always call before destruction.
    +
    7310  void Destroy(VmaAllocator allocator);
    7311 
    -
    7312  VkResult WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
    -
    7313  VkResult ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
    -
    7314 
    -
    7315  VkResult BindBufferMemory(
    -
    7316  const VmaAllocator hAllocator,
    -
    7317  const VmaAllocation hAllocation,
    -
    7318  VkDeviceSize allocationLocalOffset,
    -
    7319  VkBuffer hBuffer,
    -
    7320  const void* pNext);
    -
    7321  VkResult BindImageMemory(
    -
    7322  const VmaAllocator hAllocator,
    -
    7323  const VmaAllocation hAllocation,
    -
    7324  VkDeviceSize allocationLocalOffset,
    -
    7325  VkImage hImage,
    -
    7326  const void* pNext);
    -
    7327 
    -
    7328 private:
    -
    7329  VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
    -
    7330  uint32_t m_MemoryTypeIndex;
    -
    7331  uint32_t m_Id;
    -
    7332  VkDeviceMemory m_hMemory;
    -
    7333 
    -
    7334  /*
    -
    7335  Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory.
    -
    7336  Also protects m_MapCount, m_pMappedData.
    -
    7337  Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex.
    -
    7338  */
    -
    7339  VMA_MUTEX m_Mutex;
    -
    7340  uint32_t m_MapCount;
    -
    7341  void* m_pMappedData;
    -
    7342 };
    -
    7343 
    -
    7344 struct VmaDefragmentationMove
    -
    7345 {
    -
    7346  size_t srcBlockIndex;
    -
    7347  size_t dstBlockIndex;
    -
    7348  VkDeviceSize srcOffset;
    -
    7349  VkDeviceSize dstOffset;
    -
    7350  VkDeviceSize size;
    -
    7351  VmaAllocation hAllocation;
    -
    7352  VmaDeviceMemoryBlock* pSrcBlock;
    -
    7353  VmaDeviceMemoryBlock* pDstBlock;
    -
    7354 };
    -
    7355 
    -
    7356 class VmaDefragmentationAlgorithm;
    -
    7357 
    -
    7358 /*
    -
    7359 Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific
    -
    7360 Vulkan memory type.
    -
    7361 
    -
    7362 Synchronized internally with a mutex.
    -
    7363 */
    -
    7364 struct VmaBlockVector
    -
    7365 {
    -
    7366  VMA_CLASS_NO_COPY(VmaBlockVector)
    -
    7367 public:
    -
    7368  VmaBlockVector(
    -
    7369  VmaAllocator hAllocator,
    -
    7370  VmaPool hParentPool,
    -
    7371  uint32_t memoryTypeIndex,
    -
    7372  VkDeviceSize preferredBlockSize,
    -
    7373  size_t minBlockCount,
    -
    7374  size_t maxBlockCount,
    -
    7375  VkDeviceSize bufferImageGranularity,
    -
    7376  uint32_t frameInUseCount,
    -
    7377  bool explicitBlockSize,
    -
    7378  uint32_t algorithm,
    -
    7379  float priority,
    -
    7380  VkDeviceSize minAllocationAlignment,
    -
    7381  void* pMemoryAllocateNext);
    -
    7382  ~VmaBlockVector();
    -
    7383 
    -
    7384  VkResult CreateMinBlocks();
    -
    7385 
    -
    7386  VmaAllocator GetAllocator() const { return m_hAllocator; }
    -
    7387  VmaPool GetParentPool() const { return m_hParentPool; }
    -
    7388  bool IsCustomPool() const { return m_hParentPool != VMA_NULL; }
    -
    7389  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
    -
    7390  VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; }
    -
    7391  VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
    -
    7392  uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
    -
    7393  uint32_t GetAlgorithm() const { return m_Algorithm; }
    -
    7394 
    -
    7395  void GetPoolStats(VmaPoolStats* pStats);
    -
    7396 
    -
    7397  bool IsEmpty();
    -
    7398  bool IsCorruptionDetectionEnabled() const;
    -
    7399 
    -
    7400  VkResult Allocate(
    -
    7401  uint32_t currentFrameIndex,
    -
    7402  VkDeviceSize size,
    -
    7403  VkDeviceSize alignment,
    -
    7404  const VmaAllocationCreateInfo& createInfo,
    -
    7405  VmaSuballocationType suballocType,
    -
    7406  size_t allocationCount,
    -
    7407  VmaAllocation* pAllocations);
    -
    7408 
    -
    7409  void Free(const VmaAllocation hAllocation);
    -
    7410 
    -
    7411  // Adds statistics of this BlockVector to pStats.
    -
    7412  void AddStats(VmaStats* pStats);
    -
    7413 
    -
    7414 #if VMA_STATS_STRING_ENABLED
    -
    7415  void PrintDetailedMap(class VmaJsonWriter& json);
    -
    7416 #endif
    -
    7417 
    -
    7418  void MakePoolAllocationsLost(
    -
    7419  uint32_t currentFrameIndex,
    -
    7420  size_t* pLostAllocationCount);
    -
    7421  VkResult CheckCorruption();
    -
    7422 
    -
    7423  // Saves results in pCtx->res.
    -
    7424  void Defragment(
    -
    7425  class VmaBlockVectorDefragmentationContext* pCtx,
    -
    7426  VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags,
    -
    7427  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
    -
    7428  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
    -
    7429  VkCommandBuffer commandBuffer);
    -
    7430  void DefragmentationEnd(
    -
    7431  class VmaBlockVectorDefragmentationContext* pCtx,
    -
    7432  uint32_t flags,
    -
    7433  VmaDefragmentationStats* pStats);
    -
    7434 
    -
    7435  uint32_t ProcessDefragmentations(
    -
    7436  class VmaBlockVectorDefragmentationContext *pCtx,
    -
    7437  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves);
    -
    7438 
    -
    7439  void CommitDefragmentations(
    -
    7440  class VmaBlockVectorDefragmentationContext *pCtx,
    -
    7441  VmaDefragmentationStats* pStats);
    -
    7442 
    -
    7444  // To be used only while the m_Mutex is locked. Used during defragmentation.
    -
    7445 
    -
    7446  size_t GetBlockCount() const { return m_Blocks.size(); }
    -
    7447  VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; }
    -
    7448  size_t CalcAllocationCount() const;
    -
    7449  bool IsBufferImageGranularityConflictPossible() const;
    -
    7450 
    -
    7451 private:
    -
    7452  friend class VmaDefragmentationAlgorithm_Generic;
    +
    7312  VmaPool GetParentPool() const { return m_hParentPool; }
    +
    7313  VkDeviceMemory GetDeviceMemory() const { return m_hMemory; }
    +
    7314  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
    +
    7315  uint32_t GetId() const { return m_Id; }
    +
    7316  void* GetMappedData() const { return m_pMappedData; }
    +
    7317 
    +
    7318  // Validates all data structures inside this object. If not valid, returns false.
    +
    7319  bool Validate() const;
    +
    7320 
    +
    7321  VkResult CheckCorruption(VmaAllocator hAllocator);
    +
    7322 
    +
    7323  // ppData can be null.
    +
    7324  VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData);
    +
    7325  void Unmap(VmaAllocator hAllocator, uint32_t count);
    +
    7326 
    +
    7327  VkResult WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
    +
    7328  VkResult ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
    +
    7329 
    +
    7330  VkResult BindBufferMemory(
    +
    7331  const VmaAllocator hAllocator,
    +
    7332  const VmaAllocation hAllocation,
    +
    7333  VkDeviceSize allocationLocalOffset,
    +
    7334  VkBuffer hBuffer,
    +
    7335  const void* pNext);
    +
    7336  VkResult BindImageMemory(
    +
    7337  const VmaAllocator hAllocator,
    +
    7338  const VmaAllocation hAllocation,
    +
    7339  VkDeviceSize allocationLocalOffset,
    +
    7340  VkImage hImage,
    +
    7341  const void* pNext);
    +
    7342 
    +
    7343 private:
    +
    7344  VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
    +
    7345  uint32_t m_MemoryTypeIndex;
    +
    7346  uint32_t m_Id;
    +
    7347  VkDeviceMemory m_hMemory;
    +
    7348 
    +
    7349  /*
    +
    7350  Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory.
    +
    7351  Also protects m_MapCount, m_pMappedData.
    +
    7352  Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex.
    +
    7353  */
    +
    7354  VMA_MUTEX m_Mutex;
    +
    7355  uint32_t m_MapCount;
    +
    7356  void* m_pMappedData;
    +
    7357 };
    +
    7358 
    +
    7359 struct VmaDefragmentationMove
    +
    7360 {
    +
    7361  size_t srcBlockIndex;
    +
    7362  size_t dstBlockIndex;
    +
    7363  VkDeviceSize srcOffset;
    +
    7364  VkDeviceSize dstOffset;
    +
    7365  VkDeviceSize size;
    +
    7366  VmaAllocation hAllocation;
    +
    7367  VmaDeviceMemoryBlock* pSrcBlock;
    +
    7368  VmaDeviceMemoryBlock* pDstBlock;
    +
    7369 };
    +
    7370 
    +
    7371 class VmaDefragmentationAlgorithm;
    +
    7372 
    +
    7373 /*
    +
    7374 Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific
    +
    7375 Vulkan memory type.
    +
    7376 
    +
    7377 Synchronized internally with a mutex.
    +
    7378 */
    +
    7379 struct VmaBlockVector
    +
    7380 {
    +
    7381  VMA_CLASS_NO_COPY(VmaBlockVector)
    +
    7382 public:
    +
    7383  VmaBlockVector(
    +
    7384  VmaAllocator hAllocator,
    +
    7385  VmaPool hParentPool,
    +
    7386  uint32_t memoryTypeIndex,
    +
    7387  VkDeviceSize preferredBlockSize,
    +
    7388  size_t minBlockCount,
    +
    7389  size_t maxBlockCount,
    +
    7390  VkDeviceSize bufferImageGranularity,
    +
    7391  uint32_t frameInUseCount,
    +
    7392  bool explicitBlockSize,
    +
    7393  uint32_t algorithm,
    +
    7394  float priority,
    +
    7395  VkDeviceSize minAllocationAlignment,
    +
    7396  void* pMemoryAllocateNext);
    +
    7397  ~VmaBlockVector();
    +
    7398 
    +
    7399  VkResult CreateMinBlocks();
    +
    7400 
    +
    7401  VmaAllocator GetAllocator() const { return m_hAllocator; }
    +
    7402  VmaPool GetParentPool() const { return m_hParentPool; }
    +
    7403  bool IsCustomPool() const { return m_hParentPool != VMA_NULL; }
    +
    7404  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
    +
    7405  VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; }
    +
    7406  VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
    +
    7407  uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
    +
    7408  uint32_t GetAlgorithm() const { return m_Algorithm; }
    +
    7409 
    +
    7410  void GetPoolStats(VmaPoolStats* pStats);
    +
    7411 
    +
    7412  bool IsEmpty();
    +
    7413  bool IsCorruptionDetectionEnabled() const;
    +
    7414 
    +
    7415  VkResult Allocate(
    +
    7416  uint32_t currentFrameIndex,
    +
    7417  VkDeviceSize size,
    +
    7418  VkDeviceSize alignment,
    +
    7419  const VmaAllocationCreateInfo& createInfo,
    +
    7420  VmaSuballocationType suballocType,
    +
    7421  size_t allocationCount,
    +
    7422  VmaAllocation* pAllocations);
    +
    7423 
    +
    7424  void Free(const VmaAllocation hAllocation);
    +
    7425 
    +
    7426  // Adds statistics of this BlockVector to pStats.
    +
    7427  void AddStats(VmaStats* pStats);
    +
    7428 
    +
    7429 #if VMA_STATS_STRING_ENABLED
    +
    7430  void PrintDetailedMap(class VmaJsonWriter& json);
    +
    7431 #endif
    +
    7432 
    +
    7433  void MakePoolAllocationsLost(
    +
    7434  uint32_t currentFrameIndex,
    +
    7435  size_t* pLostAllocationCount);
    +
    7436  VkResult CheckCorruption();
    +
    7437 
    +
    7438  // Saves results in pCtx->res.
    +
    7439  void Defragment(
    +
    7440  class VmaBlockVectorDefragmentationContext* pCtx,
    +
    7441  VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags,
    +
    7442  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
    +
    7443  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
    +
    7444  VkCommandBuffer commandBuffer);
    +
    7445  void DefragmentationEnd(
    +
    7446  class VmaBlockVectorDefragmentationContext* pCtx,
    +
    7447  uint32_t flags,
    +
    7448  VmaDefragmentationStats* pStats);
    +
    7449 
    +
    7450  uint32_t ProcessDefragmentations(
    +
    7451  class VmaBlockVectorDefragmentationContext *pCtx,
    +
    7452  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves);
    7453 
    -
    7454  const VmaAllocator m_hAllocator;
    -
    7455  const VmaPool m_hParentPool;
    -
    7456  const uint32_t m_MemoryTypeIndex;
    -
    7457  const VkDeviceSize m_PreferredBlockSize;
    -
    7458  const size_t m_MinBlockCount;
    -
    7459  const size_t m_MaxBlockCount;
    -
    7460  const VkDeviceSize m_BufferImageGranularity;
    -
    7461  const uint32_t m_FrameInUseCount;
    -
    7462  const bool m_ExplicitBlockSize;
    -
    7463  const uint32_t m_Algorithm;
    -
    7464  const float m_Priority;
    -
    7465  const VkDeviceSize m_MinAllocationAlignment;
    -
    7466  void* const m_pMemoryAllocateNext;
    -
    7467  VMA_RW_MUTEX m_Mutex;
    +
    7454  void CommitDefragmentations(
    +
    7455  class VmaBlockVectorDefragmentationContext *pCtx,
    +
    7456  VmaDefragmentationStats* pStats);
    +
    7457 
    +
    7459  // To be used only while the m_Mutex is locked. Used during defragmentation.
    +
    7460 
    +
    7461  size_t GetBlockCount() const { return m_Blocks.size(); }
    +
    7462  VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; }
    +
    7463  size_t CalcAllocationCount() const;
    +
    7464  bool IsBufferImageGranularityConflictPossible() const;
    +
    7465 
    +
    7466 private:
    +
    7467  friend class VmaDefragmentationAlgorithm_Generic;
    7468 
    -
    7469  /* There can be at most one allocation that is completely empty (except when minBlockCount > 0) -
    -
    7470  a hysteresis to avoid pessimistic case of alternating creation and destruction of a VkDeviceMemory. */
    -
    7471  bool m_HasEmptyBlock;
    -
    7472  // Incrementally sorted by sumFreeSize, ascending.
    -
    7473  VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator<VmaDeviceMemoryBlock*> > m_Blocks;
    -
    7474  uint32_t m_NextBlockId;
    -
    7475 
    -
    7476  VkDeviceSize CalcMaxBlockSize() const;
    -
    7477 
    -
    7478  // Finds and removes given block from vector.
    -
    7479  void Remove(VmaDeviceMemoryBlock* pBlock);
    -
    7480 
    -
    7481  // Performs single step in sorting m_Blocks. They may not be fully sorted
    -
    7482  // after this call.
    -
    7483  void IncrementallySortBlocks();
    -
    7484 
    -
    7485  VkResult AllocatePage(
    -
    7486  uint32_t currentFrameIndex,
    -
    7487  VkDeviceSize size,
    -
    7488  VkDeviceSize alignment,
    -
    7489  const VmaAllocationCreateInfo& createInfo,
    -
    7490  VmaSuballocationType suballocType,
    -
    7491  VmaAllocation* pAllocation);
    +
    7469  const VmaAllocator m_hAllocator;
    +
    7470  const VmaPool m_hParentPool;
    +
    7471  const uint32_t m_MemoryTypeIndex;
    +
    7472  const VkDeviceSize m_PreferredBlockSize;
    +
    7473  const size_t m_MinBlockCount;
    +
    7474  const size_t m_MaxBlockCount;
    +
    7475  const VkDeviceSize m_BufferImageGranularity;
    +
    7476  const uint32_t m_FrameInUseCount;
    +
    7477  const bool m_ExplicitBlockSize;
    +
    7478  const uint32_t m_Algorithm;
    +
    7479  const float m_Priority;
    +
    7480  const VkDeviceSize m_MinAllocationAlignment;
    +
    7481  void* const m_pMemoryAllocateNext;
    +
    7482  VMA_RW_MUTEX m_Mutex;
    +
    7483 
    +
    7484  /* There can be at most one allocation that is completely empty (except when minBlockCount > 0) -
    +
    7485  a hysteresis to avoid pessimistic case of alternating creation and destruction of a VkDeviceMemory. */
    +
    7486  bool m_HasEmptyBlock;
    +
    7487  // Incrementally sorted by sumFreeSize, ascending.
    +
    7488  VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator<VmaDeviceMemoryBlock*> > m_Blocks;
    +
    7489  uint32_t m_NextBlockId;
    +
    7490 
    +
    7491  VkDeviceSize CalcMaxBlockSize() const;
    7492 
    -
    7493  // To be used only without CAN_MAKE_OTHER_LOST flag.
    -
    7494  VkResult AllocateFromBlock(
    -
    7495  VmaDeviceMemoryBlock* pBlock,
    -
    7496  uint32_t currentFrameIndex,
    -
    7497  VkDeviceSize size,
    -
    7498  VkDeviceSize alignment,
    -
    7499  VmaAllocationCreateFlags allocFlags,
    -
    7500  void* pUserData,
    -
    7501  VmaSuballocationType suballocType,
    -
    7502  uint32_t strategy,
    -
    7503  VmaAllocation* pAllocation);
    -
    7504 
    -
    7505  VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex);
    -
    7506 
    -
    7507  // Saves result to pCtx->res.
    -
    7508  void ApplyDefragmentationMovesCpu(
    -
    7509  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    -
    7510  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves);
    -
    7511  // Saves result to pCtx->res.
    -
    7512  void ApplyDefragmentationMovesGpu(
    -
    7513  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    -
    7514  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    7515  VkCommandBuffer commandBuffer);
    -
    7516 
    -
    7517  /*
    -
    7518  Used during defragmentation. pDefragmentationStats is optional. It's in/out
    -
    7519  - updated with new data.
    -
    7520  */
    -
    7521  void FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats);
    -
    7522 
    -
    7523  void UpdateHasEmptyBlock();
    -
    7524 };
    -
    7525 
    -
    7526 struct VmaPool_T
    -
    7527 {
    -
    7528  VMA_CLASS_NO_COPY(VmaPool_T)
    -
    7529 public:
    -
    7530  VmaBlockVector m_BlockVector;
    +
    7493  // Finds and removes given block from vector.
    +
    7494  void Remove(VmaDeviceMemoryBlock* pBlock);
    +
    7495 
    +
    7496  // Performs single step in sorting m_Blocks. They may not be fully sorted
    +
    7497  // after this call.
    +
    7498  void IncrementallySortBlocks();
    +
    7499 
    +
    7500  VkResult AllocatePage(
    +
    7501  uint32_t currentFrameIndex,
    +
    7502  VkDeviceSize size,
    +
    7503  VkDeviceSize alignment,
    +
    7504  const VmaAllocationCreateInfo& createInfo,
    +
    7505  VmaSuballocationType suballocType,
    +
    7506  VmaAllocation* pAllocation);
    +
    7507 
    +
    7508  // To be used only without CAN_MAKE_OTHER_LOST flag.
    +
    7509  VkResult AllocateFromBlock(
    +
    7510  VmaDeviceMemoryBlock* pBlock,
    +
    7511  uint32_t currentFrameIndex,
    +
    7512  VkDeviceSize size,
    +
    7513  VkDeviceSize alignment,
    +
    7514  VmaAllocationCreateFlags allocFlags,
    +
    7515  void* pUserData,
    +
    7516  VmaSuballocationType suballocType,
    +
    7517  uint32_t strategy,
    +
    7518  VmaAllocation* pAllocation);
    +
    7519 
    +
    7520  VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex);
    +
    7521 
    +
    7522  // Saves result to pCtx->res.
    +
    7523  void ApplyDefragmentationMovesCpu(
    +
    7524  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    +
    7525  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves);
    +
    7526  // Saves result to pCtx->res.
    +
    7527  void ApplyDefragmentationMovesGpu(
    +
    7528  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    +
    7529  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    7530  VkCommandBuffer commandBuffer);
    7531 
    -
    7532  VmaPool_T(
    -
    7533  VmaAllocator hAllocator,
    -
    7534  const VmaPoolCreateInfo& createInfo,
    -
    7535  VkDeviceSize preferredBlockSize);
    -
    7536  ~VmaPool_T();
    +
    7532  /*
    +
    7533  Used during defragmentation. pDefragmentationStats is optional. It's in/out
    +
    7534  - updated with new data.
    +
    7535  */
    +
    7536  void FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats);
    7537 
    -
    7538  uint32_t GetId() const { return m_Id; }
    -
    7539  void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; }
    +
    7538  void UpdateHasEmptyBlock();
    +
    7539 };
    7540 
    -
    7541  const char* GetName() const { return m_Name; }
    -
    7542  void SetName(const char* pName);
    -
    7543 
    -
    7544 #if VMA_STATS_STRING_ENABLED
    -
    7545  //void PrintDetailedMap(class VmaStringBuilder& sb);
    -
    7546 #endif
    -
    7547 
    -
    7548 private:
    -
    7549  uint32_t m_Id;
    -
    7550  char* m_Name;
    -
    7551  VmaPool_T* m_PrevPool = VMA_NULL;
    -
    7552  VmaPool_T* m_NextPool = VMA_NULL;
    -
    7553  friend struct VmaPoolListItemTraits;
    -
    7554 };
    +
    7541 struct VmaPool_T
    +
    7542 {
    +
    7543  VMA_CLASS_NO_COPY(VmaPool_T)
    +
    7544 public:
    +
    7545  VmaBlockVector m_BlockVector;
    +
    7546 
    +
    7547  VmaPool_T(
    +
    7548  VmaAllocator hAllocator,
    +
    7549  const VmaPoolCreateInfo& createInfo,
    +
    7550  VkDeviceSize preferredBlockSize);
    +
    7551  ~VmaPool_T();
    +
    7552 
    +
    7553  uint32_t GetId() const { return m_Id; }
    +
    7554  void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; }
    7555 
    -
    7556 struct VmaPoolListItemTraits
    -
    7557 {
    -
    7558  typedef VmaPool_T ItemType;
    -
    7559  static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
    -
    7560  static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
    -
    7561  static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
    -
    7562  static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
    -
    7563 };
    -
    7564 
    -
    7565 /*
    -
    7566 Performs defragmentation:
    -
    7567 
    -
    7568 - Updates `pBlockVector->m_pMetadata`.
    -
    7569 - Updates allocations by calling ChangeBlockAllocation() or ChangeOffset().
    -
    7570 - Does not move actual data, only returns requested moves as `moves`.
    -
    7571 */
    -
    7572 class VmaDefragmentationAlgorithm
    -
    7573 {
    -
    7574  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm)
    -
    7575 public:
    -
    7576  VmaDefragmentationAlgorithm(
    -
    7577  VmaAllocator hAllocator,
    -
    7578  VmaBlockVector* pBlockVector,
    -
    7579  uint32_t currentFrameIndex) :
    -
    7580  m_hAllocator(hAllocator),
    -
    7581  m_pBlockVector(pBlockVector),
    -
    7582  m_CurrentFrameIndex(currentFrameIndex)
    -
    7583  {
    -
    7584  }
    -
    7585  virtual ~VmaDefragmentationAlgorithm()
    -
    7586  {
    -
    7587  }
    -
    7588 
    -
    7589  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) = 0;
    -
    7590  virtual void AddAll() = 0;
    -
    7591 
    -
    7592  virtual VkResult Defragment(
    -
    7593  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    7594  VkDeviceSize maxBytesToMove,
    -
    7595  uint32_t maxAllocationsToMove,
    -
    7596  VmaDefragmentationFlags flags) = 0;
    -
    7597 
    -
    7598  virtual VkDeviceSize GetBytesMoved() const = 0;
    -
    7599  virtual uint32_t GetAllocationsMoved() const = 0;
    -
    7600 
    -
    7601 protected:
    -
    7602  VmaAllocator const m_hAllocator;
    -
    7603  VmaBlockVector* const m_pBlockVector;
    -
    7604  const uint32_t m_CurrentFrameIndex;
    -
    7605 
    -
    7606  struct AllocationInfo
    -
    7607  {
    -
    7608  VmaAllocation m_hAllocation;
    -
    7609  VkBool32* m_pChanged;
    -
    7610 
    -
    7611  AllocationInfo() :
    -
    7612  m_hAllocation(VK_NULL_HANDLE),
    -
    7613  m_pChanged(VMA_NULL)
    -
    7614  {
    -
    7615  }
    -
    7616  AllocationInfo(VmaAllocation hAlloc, VkBool32* pChanged) :
    -
    7617  m_hAllocation(hAlloc),
    -
    7618  m_pChanged(pChanged)
    -
    7619  {
    -
    7620  }
    -
    7621  };
    -
    7622 };
    -
    7623 
    -
    7624 class VmaDefragmentationAlgorithm_Generic : public VmaDefragmentationAlgorithm
    -
    7625 {
    -
    7626  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Generic)
    -
    7627 public:
    -
    7628  VmaDefragmentationAlgorithm_Generic(
    -
    7629  VmaAllocator hAllocator,
    -
    7630  VmaBlockVector* pBlockVector,
    -
    7631  uint32_t currentFrameIndex,
    -
    7632  bool overlappingMoveSupported);
    -
    7633  virtual ~VmaDefragmentationAlgorithm_Generic();
    -
    7634 
    -
    7635  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
    -
    7636  virtual void AddAll() { m_AllAllocations = true; }
    -
    7637 
    -
    7638  virtual VkResult Defragment(
    -
    7639  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    7640  VkDeviceSize maxBytesToMove,
    -
    7641  uint32_t maxAllocationsToMove,
    -
    7642  VmaDefragmentationFlags flags);
    -
    7643 
    -
    7644  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
    -
    7645  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
    -
    7646 
    -
    7647 private:
    -
    7648  uint32_t m_AllocationCount;
    -
    7649  bool m_AllAllocations;
    -
    7650 
    -
    7651  VkDeviceSize m_BytesMoved;
    -
    7652  uint32_t m_AllocationsMoved;
    -
    7653 
    -
    7654  struct AllocationInfoSizeGreater
    -
    7655  {
    -
    7656  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
    -
    7657  {
    -
    7658  return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
    -
    7659  }
    -
    7660  };
    +
    7556  const char* GetName() const { return m_Name; }
    +
    7557  void SetName(const char* pName);
    +
    7558 
    +
    7559 #if VMA_STATS_STRING_ENABLED
    +
    7560  //void PrintDetailedMap(class VmaStringBuilder& sb);
    +
    7561 #endif
    +
    7562 
    +
    7563 private:
    +
    7564  uint32_t m_Id;
    +
    7565  char* m_Name;
    +
    7566  VmaPool_T* m_PrevPool = VMA_NULL;
    +
    7567  VmaPool_T* m_NextPool = VMA_NULL;
    +
    7568  friend struct VmaPoolListItemTraits;
    +
    7569 };
    +
    7570 
    +
    7571 struct VmaPoolListItemTraits
    +
    7572 {
    +
    7573  typedef VmaPool_T ItemType;
    +
    7574  static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
    +
    7575  static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
    +
    7576  static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
    +
    7577  static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
    +
    7578 };
    +
    7579 
    +
    7580 /*
    +
    7581 Performs defragmentation:
    +
    7582 
    +
    7583 - Updates `pBlockVector->m_pMetadata`.
    +
    7584 - Updates allocations by calling ChangeBlockAllocation() or ChangeOffset().
    +
    7585 - Does not move actual data, only returns requested moves as `moves`.
    +
    7586 */
    +
    7587 class VmaDefragmentationAlgorithm
    +
    7588 {
    +
    7589  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm)
    +
    7590 public:
    +
    7591  VmaDefragmentationAlgorithm(
    +
    7592  VmaAllocator hAllocator,
    +
    7593  VmaBlockVector* pBlockVector,
    +
    7594  uint32_t currentFrameIndex) :
    +
    7595  m_hAllocator(hAllocator),
    +
    7596  m_pBlockVector(pBlockVector),
    +
    7597  m_CurrentFrameIndex(currentFrameIndex)
    +
    7598  {
    +
    7599  }
    +
    7600  virtual ~VmaDefragmentationAlgorithm()
    +
    7601  {
    +
    7602  }
    +
    7603 
    +
    7604  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) = 0;
    +
    7605  virtual void AddAll() = 0;
    +
    7606 
    +
    7607  virtual VkResult Defragment(
    +
    7608  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    7609  VkDeviceSize maxBytesToMove,
    +
    7610  uint32_t maxAllocationsToMove,
    +
    7611  VmaDefragmentationFlags flags) = 0;
    +
    7612 
    +
    7613  virtual VkDeviceSize GetBytesMoved() const = 0;
    +
    7614  virtual uint32_t GetAllocationsMoved() const = 0;
    +
    7615 
    +
    7616 protected:
    +
    7617  VmaAllocator const m_hAllocator;
    +
    7618  VmaBlockVector* const m_pBlockVector;
    +
    7619  const uint32_t m_CurrentFrameIndex;
    +
    7620 
    +
    7621  struct AllocationInfo
    +
    7622  {
    +
    7623  VmaAllocation m_hAllocation;
    +
    7624  VkBool32* m_pChanged;
    +
    7625 
    +
    7626  AllocationInfo() :
    +
    7627  m_hAllocation(VK_NULL_HANDLE),
    +
    7628  m_pChanged(VMA_NULL)
    +
    7629  {
    +
    7630  }
    +
    7631  AllocationInfo(VmaAllocation hAlloc, VkBool32* pChanged) :
    +
    7632  m_hAllocation(hAlloc),
    +
    7633  m_pChanged(pChanged)
    +
    7634  {
    +
    7635  }
    +
    7636  };
    +
    7637 };
    +
    7638 
    +
    7639 class VmaDefragmentationAlgorithm_Generic : public VmaDefragmentationAlgorithm
    +
    7640 {
    +
    7641  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Generic)
    +
    7642 public:
    +
    7643  VmaDefragmentationAlgorithm_Generic(
    +
    7644  VmaAllocator hAllocator,
    +
    7645  VmaBlockVector* pBlockVector,
    +
    7646  uint32_t currentFrameIndex,
    +
    7647  bool overlappingMoveSupported);
    +
    7648  virtual ~VmaDefragmentationAlgorithm_Generic();
    +
    7649 
    +
    7650  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
    +
    7651  virtual void AddAll() { m_AllAllocations = true; }
    +
    7652 
    +
    7653  virtual VkResult Defragment(
    +
    7654  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    7655  VkDeviceSize maxBytesToMove,
    +
    7656  uint32_t maxAllocationsToMove,
    +
    7657  VmaDefragmentationFlags flags);
    +
    7658 
    +
    7659  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
    +
    7660  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
    7661 
    -
    7662  struct AllocationInfoOffsetGreater
    -
    7663  {
    -
    7664  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
    -
    7665  {
    -
    7666  return lhs.m_hAllocation->GetOffset() > rhs.m_hAllocation->GetOffset();
    -
    7667  }
    -
    7668  };
    -
    7669 
    -
    7670  struct BlockInfo
    -
    7671  {
    -
    7672  size_t m_OriginalBlockIndex;
    -
    7673  VmaDeviceMemoryBlock* m_pBlock;
    -
    7674  bool m_HasNonMovableAllocations;
    -
    7675  VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
    +
    7662 private:
    +
    7663  uint32_t m_AllocationCount;
    +
    7664  bool m_AllAllocations;
    +
    7665 
    +
    7666  VkDeviceSize m_BytesMoved;
    +
    7667  uint32_t m_AllocationsMoved;
    +
    7668 
    +
    7669  struct AllocationInfoSizeGreater
    +
    7670  {
    +
    7671  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
    +
    7672  {
    +
    7673  return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
    +
    7674  }
    +
    7675  };
    7676 
    -
    7677  BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) :
    -
    7678  m_OriginalBlockIndex(SIZE_MAX),
    -
    7679  m_pBlock(VMA_NULL),
    -
    7680  m_HasNonMovableAllocations(true),
    -
    7681  m_Allocations(pAllocationCallbacks)
    -
    7682  {
    -
    7683  }
    +
    7677  struct AllocationInfoOffsetGreater
    +
    7678  {
    +
    7679  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
    +
    7680  {
    +
    7681  return lhs.m_hAllocation->GetOffset() > rhs.m_hAllocation->GetOffset();
    +
    7682  }
    +
    7683  };
    7684 
    -
    7685  void CalcHasNonMovableAllocations()
    -
    7686  {
    -
    7687  const size_t blockAllocCount = m_pBlock->m_pMetadata->GetAllocationCount();
    -
    7688  const size_t defragmentAllocCount = m_Allocations.size();
    -
    7689  m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
    -
    7690  }
    +
    7685  struct BlockInfo
    +
    7686  {
    +
    7687  size_t m_OriginalBlockIndex;
    +
    7688  VmaDeviceMemoryBlock* m_pBlock;
    +
    7689  bool m_HasNonMovableAllocations;
    +
    7690  VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
    7691 
    -
    7692  void SortAllocationsBySizeDescending()
    -
    7693  {
    -
    7694  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
    -
    7695  }
    -
    7696 
    -
    7697  void SortAllocationsByOffsetDescending()
    -
    7698  {
    -
    7699  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoOffsetGreater());
    -
    7700  }
    -
    7701  };
    -
    7702 
    -
    7703  struct BlockPointerLess
    -
    7704  {
    -
    7705  bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const
    -
    7706  {
    -
    7707  return pLhsBlockInfo->m_pBlock < pRhsBlock;
    -
    7708  }
    -
    7709  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
    -
    7710  {
    -
    7711  return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
    -
    7712  }
    -
    7713  };
    -
    7714 
    -
    7715  // 1. Blocks with some non-movable allocations go first.
    -
    7716  // 2. Blocks with smaller sumFreeSize go first.
    -
    7717  struct BlockInfoCompareMoveDestination
    -
    7718  {
    -
    7719  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
    -
    7720  {
    -
    7721  if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
    -
    7722  {
    -
    7723  return true;
    -
    7724  }
    -
    7725  if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
    -
    7726  {
    -
    7727  return false;
    -
    7728  }
    -
    7729  if(pLhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize())
    -
    7730  {
    -
    7731  return true;
    -
    7732  }
    -
    7733  return false;
    -
    7734  }
    -
    7735  };
    -
    7736 
    -
    7737  typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
    -
    7738  BlockInfoVector m_Blocks;
    -
    7739 
    -
    7740  VkResult DefragmentRound(
    -
    7741  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    7742  VkDeviceSize maxBytesToMove,
    -
    7743  uint32_t maxAllocationsToMove,
    -
    7744  bool freeOldAllocations);
    -
    7745 
    -
    7746  size_t CalcBlocksWithNonMovableCount() const;
    -
    7747 
    -
    7748  static bool MoveMakesSense(
    -
    7749  size_t dstBlockIndex, VkDeviceSize dstOffset,
    -
    7750  size_t srcBlockIndex, VkDeviceSize srcOffset);
    -
    7751 };
    -
    7752 
    -
    7753 class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm
    -
    7754 {
    -
    7755  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Fast)
    -
    7756 public:
    -
    7757  VmaDefragmentationAlgorithm_Fast(
    -
    7758  VmaAllocator hAllocator,
    -
    7759  VmaBlockVector* pBlockVector,
    -
    7760  uint32_t currentFrameIndex,
    -
    7761  bool overlappingMoveSupported);
    -
    7762  virtual ~VmaDefragmentationAlgorithm_Fast();
    -
    7763 
    -
    7764  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) { ++m_AllocationCount; }
    -
    7765  virtual void AddAll() { m_AllAllocations = true; }
    -
    7766 
    -
    7767  virtual VkResult Defragment(
    -
    7768  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    7769  VkDeviceSize maxBytesToMove,
    -
    7770  uint32_t maxAllocationsToMove,
    -
    7771  VmaDefragmentationFlags flags);
    -
    7772 
    -
    7773  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
    -
    7774  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
    -
    7775 
    -
    7776 private:
    -
    7777  struct BlockInfo
    -
    7778  {
    -
    7779  size_t origBlockIndex;
    -
    7780  };
    +
    7692  BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) :
    +
    7693  m_OriginalBlockIndex(SIZE_MAX),
    +
    7694  m_pBlock(VMA_NULL),
    +
    7695  m_HasNonMovableAllocations(true),
    +
    7696  m_Allocations(pAllocationCallbacks)
    +
    7697  {
    +
    7698  }
    +
    7699 
    +
    7700  void CalcHasNonMovableAllocations()
    +
    7701  {
    +
    7702  const size_t blockAllocCount = m_pBlock->m_pMetadata->GetAllocationCount();
    +
    7703  const size_t defragmentAllocCount = m_Allocations.size();
    +
    7704  m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
    +
    7705  }
    +
    7706 
    +
    7707  void SortAllocationsBySizeDescending()
    +
    7708  {
    +
    7709  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
    +
    7710  }
    +
    7711 
    +
    7712  void SortAllocationsByOffsetDescending()
    +
    7713  {
    +
    7714  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoOffsetGreater());
    +
    7715  }
    +
    7716  };
    +
    7717 
    +
    7718  struct BlockPointerLess
    +
    7719  {
    +
    7720  bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const
    +
    7721  {
    +
    7722  return pLhsBlockInfo->m_pBlock < pRhsBlock;
    +
    7723  }
    +
    7724  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
    +
    7725  {
    +
    7726  return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
    +
    7727  }
    +
    7728  };
    +
    7729 
    +
    7730  // 1. Blocks with some non-movable allocations go first.
    +
    7731  // 2. Blocks with smaller sumFreeSize go first.
    +
    7732  struct BlockInfoCompareMoveDestination
    +
    7733  {
    +
    7734  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
    +
    7735  {
    +
    7736  if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
    +
    7737  {
    +
    7738  return true;
    +
    7739  }
    +
    7740  if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
    +
    7741  {
    +
    7742  return false;
    +
    7743  }
    +
    7744  if(pLhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize())
    +
    7745  {
    +
    7746  return true;
    +
    7747  }
    +
    7748  return false;
    +
    7749  }
    +
    7750  };
    +
    7751 
    +
    7752  typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
    +
    7753  BlockInfoVector m_Blocks;
    +
    7754 
    +
    7755  VkResult DefragmentRound(
    +
    7756  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    7757  VkDeviceSize maxBytesToMove,
    +
    7758  uint32_t maxAllocationsToMove,
    +
    7759  bool freeOldAllocations);
    +
    7760 
    +
    7761  size_t CalcBlocksWithNonMovableCount() const;
    +
    7762 
    +
    7763  static bool MoveMakesSense(
    +
    7764  size_t dstBlockIndex, VkDeviceSize dstOffset,
    +
    7765  size_t srcBlockIndex, VkDeviceSize srcOffset);
    +
    7766 };
    +
    7767 
    +
    7768 class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm
    +
    7769 {
    +
    7770  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Fast)
    +
    7771 public:
    +
    7772  VmaDefragmentationAlgorithm_Fast(
    +
    7773  VmaAllocator hAllocator,
    +
    7774  VmaBlockVector* pBlockVector,
    +
    7775  uint32_t currentFrameIndex,
    +
    7776  bool overlappingMoveSupported);
    +
    7777  virtual ~VmaDefragmentationAlgorithm_Fast();
    +
    7778 
    +
    7779  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) { ++m_AllocationCount; }
    +
    7780  virtual void AddAll() { m_AllAllocations = true; }
    7781 
    -
    7782  class FreeSpaceDatabase
    -
    7783  {
    -
    7784  public:
    -
    7785  FreeSpaceDatabase()
    -
    7786  {
    -
    7787  FreeSpace s = {};
    -
    7788  s.blockInfoIndex = SIZE_MAX;
    -
    7789  for(size_t i = 0; i < MAX_COUNT; ++i)
    -
    7790  {
    -
    7791  m_FreeSpaces[i] = s;
    -
    7792  }
    -
    7793  }
    -
    7794 
    -
    7795  void Register(size_t blockInfoIndex, VkDeviceSize offset, VkDeviceSize size)
    -
    7796  {
    -
    7797  if(size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    7798  {
    -
    7799  return;
    -
    7800  }
    -
    7801 
    -
    7802  // Find first invalid or the smallest structure.
    -
    7803  size_t bestIndex = SIZE_MAX;
    +
    7782  virtual VkResult Defragment(
    +
    7783  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    7784  VkDeviceSize maxBytesToMove,
    +
    7785  uint32_t maxAllocationsToMove,
    +
    7786  VmaDefragmentationFlags flags);
    +
    7787 
    +
    7788  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
    +
    7789  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
    +
    7790 
    +
    7791 private:
    +
    7792  struct BlockInfo
    +
    7793  {
    +
    7794  size_t origBlockIndex;
    +
    7795  };
    +
    7796 
    +
    7797  class FreeSpaceDatabase
    +
    7798  {
    +
    7799  public:
    +
    7800  FreeSpaceDatabase()
    +
    7801  {
    +
    7802  FreeSpace s = {};
    +
    7803  s.blockInfoIndex = SIZE_MAX;
    7804  for(size_t i = 0; i < MAX_COUNT; ++i)
    7805  {
    -
    7806  // Empty structure.
    -
    7807  if(m_FreeSpaces[i].blockInfoIndex == SIZE_MAX)
    -
    7808  {
    -
    7809  bestIndex = i;
    -
    7810  break;
    -
    7811  }
    -
    7812  if(m_FreeSpaces[i].size < size &&
    -
    7813  (bestIndex == SIZE_MAX || m_FreeSpaces[bestIndex].size > m_FreeSpaces[i].size))
    -
    7814  {
    -
    7815  bestIndex = i;
    -
    7816  }
    -
    7817  }
    -
    7818 
    -
    7819  if(bestIndex != SIZE_MAX)
    +
    7806  m_FreeSpaces[i] = s;
    +
    7807  }
    +
    7808  }
    +
    7809 
    +
    7810  void Register(size_t blockInfoIndex, VkDeviceSize offset, VkDeviceSize size)
    +
    7811  {
    +
    7812  if(size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    7813  {
    +
    7814  return;
    +
    7815  }
    +
    7816 
    +
    7817  // Find first invalid or the smallest structure.
    +
    7818  size_t bestIndex = SIZE_MAX;
    +
    7819  for(size_t i = 0; i < MAX_COUNT; ++i)
    7820  {
    -
    7821  m_FreeSpaces[bestIndex].blockInfoIndex = blockInfoIndex;
    -
    7822  m_FreeSpaces[bestIndex].offset = offset;
    -
    7823  m_FreeSpaces[bestIndex].size = size;
    -
    7824  }
    -
    7825  }
    -
    7826 
    -
    7827  bool Fetch(VkDeviceSize alignment, VkDeviceSize size,
    -
    7828  size_t& outBlockInfoIndex, VkDeviceSize& outDstOffset)
    -
    7829  {
    -
    7830  size_t bestIndex = SIZE_MAX;
    -
    7831  VkDeviceSize bestFreeSpaceAfter = 0;
    -
    7832  for(size_t i = 0; i < MAX_COUNT; ++i)
    -
    7833  {
    -
    7834  // Structure is valid.
    -
    7835  if(m_FreeSpaces[i].blockInfoIndex != SIZE_MAX)
    -
    7836  {
    -
    7837  const VkDeviceSize dstOffset = VmaAlignUp(m_FreeSpaces[i].offset, alignment);
    -
    7838  // Allocation fits into this structure.
    -
    7839  if(dstOffset + size <= m_FreeSpaces[i].offset + m_FreeSpaces[i].size)
    -
    7840  {
    -
    7841  const VkDeviceSize freeSpaceAfter = (m_FreeSpaces[i].offset + m_FreeSpaces[i].size) -
    -
    7842  (dstOffset + size);
    -
    7843  if(bestIndex == SIZE_MAX || freeSpaceAfter > bestFreeSpaceAfter)
    -
    7844  {
    -
    7845  bestIndex = i;
    -
    7846  bestFreeSpaceAfter = freeSpaceAfter;
    -
    7847  }
    -
    7848  }
    -
    7849  }
    -
    7850  }
    -
    7851 
    -
    7852  if(bestIndex != SIZE_MAX)
    -
    7853  {
    -
    7854  outBlockInfoIndex = m_FreeSpaces[bestIndex].blockInfoIndex;
    -
    7855  outDstOffset = VmaAlignUp(m_FreeSpaces[bestIndex].offset, alignment);
    -
    7856 
    -
    7857  if(bestFreeSpaceAfter >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    7858  {
    -
    7859  // Leave this structure for remaining empty space.
    -
    7860  const VkDeviceSize alignmentPlusSize = (outDstOffset - m_FreeSpaces[bestIndex].offset) + size;
    -
    7861  m_FreeSpaces[bestIndex].offset += alignmentPlusSize;
    -
    7862  m_FreeSpaces[bestIndex].size -= alignmentPlusSize;
    -
    7863  }
    -
    7864  else
    -
    7865  {
    -
    7866  // This structure becomes invalid.
    -
    7867  m_FreeSpaces[bestIndex].blockInfoIndex = SIZE_MAX;
    -
    7868  }
    -
    7869 
    -
    7870  return true;
    -
    7871  }
    -
    7872 
    -
    7873  return false;
    -
    7874  }
    -
    7875 
    -
    7876  private:
    -
    7877  static const size_t MAX_COUNT = 4;
    -
    7878 
    -
    7879  struct FreeSpace
    -
    7880  {
    -
    7881  size_t blockInfoIndex; // SIZE_MAX means this structure is invalid.
    -
    7882  VkDeviceSize offset;
    -
    7883  VkDeviceSize size;
    -
    7884  } m_FreeSpaces[MAX_COUNT];
    -
    7885  };
    -
    7886 
    -
    7887  const bool m_OverlappingMoveSupported;
    -
    7888 
    -
    7889  uint32_t m_AllocationCount;
    -
    7890  bool m_AllAllocations;
    -
    7891 
    -
    7892  VkDeviceSize m_BytesMoved;
    -
    7893  uint32_t m_AllocationsMoved;
    -
    7894 
    -
    7895  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> > m_BlockInfos;
    -
    7896 
    -
    7897  void PreprocessMetadata();
    -
    7898  void PostprocessMetadata();
    -
    7899  void InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc);
    -
    7900 };
    +
    7821  // Empty structure.
    +
    7822  if(m_FreeSpaces[i].blockInfoIndex == SIZE_MAX)
    +
    7823  {
    +
    7824  bestIndex = i;
    +
    7825  break;
    +
    7826  }
    +
    7827  if(m_FreeSpaces[i].size < size &&
    +
    7828  (bestIndex == SIZE_MAX || m_FreeSpaces[bestIndex].size > m_FreeSpaces[i].size))
    +
    7829  {
    +
    7830  bestIndex = i;
    +
    7831  }
    +
    7832  }
    +
    7833 
    +
    7834  if(bestIndex != SIZE_MAX)
    +
    7835  {
    +
    7836  m_FreeSpaces[bestIndex].blockInfoIndex = blockInfoIndex;
    +
    7837  m_FreeSpaces[bestIndex].offset = offset;
    +
    7838  m_FreeSpaces[bestIndex].size = size;
    +
    7839  }
    +
    7840  }
    +
    7841 
    +
    7842  bool Fetch(VkDeviceSize alignment, VkDeviceSize size,
    +
    7843  size_t& outBlockInfoIndex, VkDeviceSize& outDstOffset)
    +
    7844  {
    +
    7845  size_t bestIndex = SIZE_MAX;
    +
    7846  VkDeviceSize bestFreeSpaceAfter = 0;
    +
    7847  for(size_t i = 0; i < MAX_COUNT; ++i)
    +
    7848  {
    +
    7849  // Structure is valid.
    +
    7850  if(m_FreeSpaces[i].blockInfoIndex != SIZE_MAX)
    +
    7851  {
    +
    7852  const VkDeviceSize dstOffset = VmaAlignUp(m_FreeSpaces[i].offset, alignment);
    +
    7853  // Allocation fits into this structure.
    +
    7854  if(dstOffset + size <= m_FreeSpaces[i].offset + m_FreeSpaces[i].size)
    +
    7855  {
    +
    7856  const VkDeviceSize freeSpaceAfter = (m_FreeSpaces[i].offset + m_FreeSpaces[i].size) -
    +
    7857  (dstOffset + size);
    +
    7858  if(bestIndex == SIZE_MAX || freeSpaceAfter > bestFreeSpaceAfter)
    +
    7859  {
    +
    7860  bestIndex = i;
    +
    7861  bestFreeSpaceAfter = freeSpaceAfter;
    +
    7862  }
    +
    7863  }
    +
    7864  }
    +
    7865  }
    +
    7866 
    +
    7867  if(bestIndex != SIZE_MAX)
    +
    7868  {
    +
    7869  outBlockInfoIndex = m_FreeSpaces[bestIndex].blockInfoIndex;
    +
    7870  outDstOffset = VmaAlignUp(m_FreeSpaces[bestIndex].offset, alignment);
    +
    7871 
    +
    7872  if(bestFreeSpaceAfter >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    7873  {
    +
    7874  // Leave this structure for remaining empty space.
    +
    7875  const VkDeviceSize alignmentPlusSize = (outDstOffset - m_FreeSpaces[bestIndex].offset) + size;
    +
    7876  m_FreeSpaces[bestIndex].offset += alignmentPlusSize;
    +
    7877  m_FreeSpaces[bestIndex].size -= alignmentPlusSize;
    +
    7878  }
    +
    7879  else
    +
    7880  {
    +
    7881  // This structure becomes invalid.
    +
    7882  m_FreeSpaces[bestIndex].blockInfoIndex = SIZE_MAX;
    +
    7883  }
    +
    7884 
    +
    7885  return true;
    +
    7886  }
    +
    7887 
    +
    7888  return false;
    +
    7889  }
    +
    7890 
    +
    7891  private:
    +
    7892  static const size_t MAX_COUNT = 4;
    +
    7893 
    +
    7894  struct FreeSpace
    +
    7895  {
    +
    7896  size_t blockInfoIndex; // SIZE_MAX means this structure is invalid.
    +
    7897  VkDeviceSize offset;
    +
    7898  VkDeviceSize size;
    +
    7899  } m_FreeSpaces[MAX_COUNT];
    +
    7900  };
    7901 
    -
    7902 struct VmaBlockDefragmentationContext
    -
    7903 {
    -
    7904  enum BLOCK_FLAG
    -
    7905  {
    -
    7906  BLOCK_FLAG_USED = 0x00000001,
    -
    7907  };
    -
    7908  uint32_t flags;
    -
    7909  VkBuffer hBuffer;
    -
    7910 };
    +
    7902  const bool m_OverlappingMoveSupported;
    +
    7903 
    +
    7904  uint32_t m_AllocationCount;
    +
    7905  bool m_AllAllocations;
    +
    7906 
    +
    7907  VkDeviceSize m_BytesMoved;
    +
    7908  uint32_t m_AllocationsMoved;
    +
    7909 
    +
    7910  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> > m_BlockInfos;
    7911 
    -
    7912 class VmaBlockVectorDefragmentationContext
    -
    7913 {
    -
    7914  VMA_CLASS_NO_COPY(VmaBlockVectorDefragmentationContext)
    -
    7915 public:
    -
    7916  VkResult res;
    -
    7917  bool mutexLocked;
    -
    7918  VmaVector< VmaBlockDefragmentationContext, VmaStlAllocator<VmaBlockDefragmentationContext> > blockContexts;
    -
    7919  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> > defragmentationMoves;
    -
    7920  uint32_t defragmentationMovesProcessed;
    -
    7921  uint32_t defragmentationMovesCommitted;
    -
    7922  bool hasDefragmentationPlan;
    -
    7923 
    -
    7924  VmaBlockVectorDefragmentationContext(
    -
    7925  VmaAllocator hAllocator,
    -
    7926  VmaPool hCustomPool, // Optional.
    -
    7927  VmaBlockVector* pBlockVector,
    -
    7928  uint32_t currFrameIndex);
    -
    7929  ~VmaBlockVectorDefragmentationContext();
    -
    7930 
    -
    7931  VmaPool GetCustomPool() const { return m_hCustomPool; }
    -
    7932  VmaBlockVector* GetBlockVector() const { return m_pBlockVector; }
    -
    7933  VmaDefragmentationAlgorithm* GetAlgorithm() const { return m_pAlgorithm; }
    -
    7934 
    -
    7935  void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
    -
    7936  void AddAll() { m_AllAllocations = true; }
    -
    7937 
    -
    7938  void Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags);
    -
    7939 
    -
    7940 private:
    -
    7941  const VmaAllocator m_hAllocator;
    -
    7942  // Null if not from custom pool.
    -
    7943  const VmaPool m_hCustomPool;
    -
    7944  // Redundant, for convenience not to fetch from m_hCustomPool->m_BlockVector or m_hAllocator->m_pBlockVectors.
    -
    7945  VmaBlockVector* const m_pBlockVector;
    -
    7946  const uint32_t m_CurrFrameIndex;
    -
    7947  // Owner of this object.
    -
    7948  VmaDefragmentationAlgorithm* m_pAlgorithm;
    +
    7912  void PreprocessMetadata();
    +
    7913  void PostprocessMetadata();
    +
    7914  void InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc);
    +
    7915 };
    +
    7916 
    +
    7917 struct VmaBlockDefragmentationContext
    +
    7918 {
    +
    7919  enum BLOCK_FLAG
    +
    7920  {
    +
    7921  BLOCK_FLAG_USED = 0x00000001,
    +
    7922  };
    +
    7923  uint32_t flags;
    +
    7924  VkBuffer hBuffer;
    +
    7925 };
    +
    7926 
    +
    7927 class VmaBlockVectorDefragmentationContext
    +
    7928 {
    +
    7929  VMA_CLASS_NO_COPY(VmaBlockVectorDefragmentationContext)
    +
    7930 public:
    +
    7931  VkResult res;
    +
    7932  bool mutexLocked;
    +
    7933  VmaVector< VmaBlockDefragmentationContext, VmaStlAllocator<VmaBlockDefragmentationContext> > blockContexts;
    +
    7934  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> > defragmentationMoves;
    +
    7935  uint32_t defragmentationMovesProcessed;
    +
    7936  uint32_t defragmentationMovesCommitted;
    +
    7937  bool hasDefragmentationPlan;
    +
    7938 
    +
    7939  VmaBlockVectorDefragmentationContext(
    +
    7940  VmaAllocator hAllocator,
    +
    7941  VmaPool hCustomPool, // Optional.
    +
    7942  VmaBlockVector* pBlockVector,
    +
    7943  uint32_t currFrameIndex);
    +
    7944  ~VmaBlockVectorDefragmentationContext();
    +
    7945 
    +
    7946  VmaPool GetCustomPool() const { return m_hCustomPool; }
    +
    7947  VmaBlockVector* GetBlockVector() const { return m_pBlockVector; }
    +
    7948  VmaDefragmentationAlgorithm* GetAlgorithm() const { return m_pAlgorithm; }
    7949 
    -
    7950  struct AllocInfo
    -
    7951  {
    -
    7952  VmaAllocation hAlloc;
    -
    7953  VkBool32* pChanged;
    -
    7954  };
    -
    7955  // Used between constructor and Begin.
    -
    7956  VmaVector< AllocInfo, VmaStlAllocator<AllocInfo> > m_Allocations;
    -
    7957  bool m_AllAllocations;
    -
    7958 };
    -
    7959 
    -
    7960 struct VmaDefragmentationContext_T
    -
    7961 {
    -
    7962 private:
    -
    7963  VMA_CLASS_NO_COPY(VmaDefragmentationContext_T)
    -
    7964 public:
    -
    7965  VmaDefragmentationContext_T(
    -
    7966  VmaAllocator hAllocator,
    -
    7967  uint32_t currFrameIndex,
    -
    7968  uint32_t flags,
    -
    7969  VmaDefragmentationStats* pStats);
    -
    7970  ~VmaDefragmentationContext_T();
    -
    7971 
    -
    7972  void AddPools(uint32_t poolCount, const VmaPool* pPools);
    -
    7973  void AddAllocations(
    -
    7974  uint32_t allocationCount,
    -
    7975  const VmaAllocation* pAllocations,
    -
    7976  VkBool32* pAllocationsChanged);
    -
    7977 
    -
    7978  /*
    -
    7979  Returns:
    -
    7980  - `VK_SUCCESS` if succeeded and object can be destroyed immediately.
    -
    7981  - `VK_NOT_READY` if succeeded but the object must remain alive until vmaDefragmentationEnd().
    -
    7982  - Negative value if error occurred and object can be destroyed immediately.
    -
    7983  */
    -
    7984  VkResult Defragment(
    -
    7985  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
    -
    7986  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
    -
    7987  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags);
    -
    7988 
    -
    7989  VkResult DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo);
    -
    7990  VkResult DefragmentPassEnd();
    -
    7991 
    -
    7992 private:
    -
    7993  const VmaAllocator m_hAllocator;
    -
    7994  const uint32_t m_CurrFrameIndex;
    -
    7995  const uint32_t m_Flags;
    -
    7996  VmaDefragmentationStats* const m_pStats;
    -
    7997 
    -
    7998  VkDeviceSize m_MaxCpuBytesToMove;
    -
    7999  uint32_t m_MaxCpuAllocationsToMove;
    -
    8000  VkDeviceSize m_MaxGpuBytesToMove;
    -
    8001  uint32_t m_MaxGpuAllocationsToMove;
    -
    8002 
    -
    8003  // Owner of these objects.
    -
    8004  VmaBlockVectorDefragmentationContext* m_DefaultPoolContexts[VK_MAX_MEMORY_TYPES];
    -
    8005  // Owner of these objects.
    -
    8006  VmaVector< VmaBlockVectorDefragmentationContext*, VmaStlAllocator<VmaBlockVectorDefragmentationContext*> > m_CustomPoolContexts;
    -
    8007 };
    -
    8008 
    -
    8009 #if VMA_RECORDING_ENABLED
    -
    8010 
    -
    8011 class VmaRecorder
    -
    8012 {
    -
    8013 public:
    -
    8014  VmaRecorder();
    -
    8015  VkResult Init(const VmaRecordSettings& settings, bool useMutex);
    -
    8016  void WriteConfiguration(
    -
    8017  const VkPhysicalDeviceProperties& devProps,
    -
    8018  const VkPhysicalDeviceMemoryProperties& memProps,
    -
    8019  uint32_t vulkanApiVersion,
    -
    8020  bool dedicatedAllocationExtensionEnabled,
    -
    8021  bool bindMemory2ExtensionEnabled,
    -
    8022  bool memoryBudgetExtensionEnabled,
    -
    8023  bool deviceCoherentMemoryExtensionEnabled);
    -
    8024  ~VmaRecorder();
    +
    7950  void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
    +
    7951  void AddAll() { m_AllAllocations = true; }
    +
    7952 
    +
    7953  void Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags);
    +
    7954 
    +
    7955 private:
    +
    7956  const VmaAllocator m_hAllocator;
    +
    7957  // Null if not from custom pool.
    +
    7958  const VmaPool m_hCustomPool;
    +
    7959  // Redundant, for convenience not to fetch from m_hCustomPool->m_BlockVector or m_hAllocator->m_pBlockVectors.
    +
    7960  VmaBlockVector* const m_pBlockVector;
    +
    7961  const uint32_t m_CurrFrameIndex;
    +
    7962  // Owner of this object.
    +
    7963  VmaDefragmentationAlgorithm* m_pAlgorithm;
    +
    7964 
    +
    7965  struct AllocInfo
    +
    7966  {
    +
    7967  VmaAllocation hAlloc;
    +
    7968  VkBool32* pChanged;
    +
    7969  };
    +
    7970  // Used between constructor and Begin.
    +
    7971  VmaVector< AllocInfo, VmaStlAllocator<AllocInfo> > m_Allocations;
    +
    7972  bool m_AllAllocations;
    +
    7973 };
    +
    7974 
    +
    7975 struct VmaDefragmentationContext_T
    +
    7976 {
    +
    7977 private:
    +
    7978  VMA_CLASS_NO_COPY(VmaDefragmentationContext_T)
    +
    7979 public:
    +
    7980  VmaDefragmentationContext_T(
    +
    7981  VmaAllocator hAllocator,
    +
    7982  uint32_t currFrameIndex,
    +
    7983  uint32_t flags,
    +
    7984  VmaDefragmentationStats* pStats);
    +
    7985  ~VmaDefragmentationContext_T();
    +
    7986 
    +
    7987  void AddPools(uint32_t poolCount, const VmaPool* pPools);
    +
    7988  void AddAllocations(
    +
    7989  uint32_t allocationCount,
    +
    7990  const VmaAllocation* pAllocations,
    +
    7991  VkBool32* pAllocationsChanged);
    +
    7992 
    +
    7993  /*
    +
    7994  Returns:
    +
    7995  - `VK_SUCCESS` if succeeded and object can be destroyed immediately.
    +
    7996  - `VK_NOT_READY` if succeeded but the object must remain alive until vmaDefragmentationEnd().
    +
    7997  - Negative value if error occurred and object can be destroyed immediately.
    +
    7998  */
    +
    7999  VkResult Defragment(
    +
    8000  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
    +
    8001  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
    +
    8002  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags);
    +
    8003 
    +
    8004  VkResult DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo);
    +
    8005  VkResult DefragmentPassEnd();
    +
    8006 
    +
    8007 private:
    +
    8008  const VmaAllocator m_hAllocator;
    +
    8009  const uint32_t m_CurrFrameIndex;
    +
    8010  const uint32_t m_Flags;
    +
    8011  VmaDefragmentationStats* const m_pStats;
    +
    8012 
    +
    8013  VkDeviceSize m_MaxCpuBytesToMove;
    +
    8014  uint32_t m_MaxCpuAllocationsToMove;
    +
    8015  VkDeviceSize m_MaxGpuBytesToMove;
    +
    8016  uint32_t m_MaxGpuAllocationsToMove;
    +
    8017 
    +
    8018  // Owner of these objects.
    +
    8019  VmaBlockVectorDefragmentationContext* m_DefaultPoolContexts[VK_MAX_MEMORY_TYPES];
    +
    8020  // Owner of these objects.
    +
    8021  VmaVector< VmaBlockVectorDefragmentationContext*, VmaStlAllocator<VmaBlockVectorDefragmentationContext*> > m_CustomPoolContexts;
    +
    8022 };
    +
    8023 
    +
    8024 #if VMA_RECORDING_ENABLED
    8025 
    -
    8026  void RecordCreateAllocator(uint32_t frameIndex);
    -
    8027  void RecordDestroyAllocator(uint32_t frameIndex);
    -
    8028  void RecordCreatePool(uint32_t frameIndex,
    -
    8029  const VmaPoolCreateInfo& createInfo,
    -
    8030  VmaPool pool);
    -
    8031  void RecordDestroyPool(uint32_t frameIndex, VmaPool pool);
    -
    8032  void RecordAllocateMemory(uint32_t frameIndex,
    -
    8033  const VkMemoryRequirements& vkMemReq,
    -
    8034  const VmaAllocationCreateInfo& createInfo,
    -
    8035  VmaAllocation allocation);
    -
    8036  void RecordAllocateMemoryPages(uint32_t frameIndex,
    -
    8037  const VkMemoryRequirements& vkMemReq,
    -
    8038  const VmaAllocationCreateInfo& createInfo,
    -
    8039  uint64_t allocationCount,
    -
    8040  const VmaAllocation* pAllocations);
    -
    8041  void RecordAllocateMemoryForBuffer(uint32_t frameIndex,
    -
    8042  const VkMemoryRequirements& vkMemReq,
    -
    8043  bool requiresDedicatedAllocation,
    -
    8044  bool prefersDedicatedAllocation,
    -
    8045  const VmaAllocationCreateInfo& createInfo,
    -
    8046  VmaAllocation allocation);
    -
    8047  void RecordAllocateMemoryForImage(uint32_t frameIndex,
    +
    8026 class VmaRecorder
    +
    8027 {
    +
    8028 public:
    +
    8029  VmaRecorder();
    +
    8030  VkResult Init(const VmaRecordSettings& settings, bool useMutex);
    +
    8031  void WriteConfiguration(
    +
    8032  const VkPhysicalDeviceProperties& devProps,
    +
    8033  const VkPhysicalDeviceMemoryProperties& memProps,
    +
    8034  uint32_t vulkanApiVersion,
    +
    8035  bool dedicatedAllocationExtensionEnabled,
    +
    8036  bool bindMemory2ExtensionEnabled,
    +
    8037  bool memoryBudgetExtensionEnabled,
    +
    8038  bool deviceCoherentMemoryExtensionEnabled);
    +
    8039  ~VmaRecorder();
    +
    8040 
    +
    8041  void RecordCreateAllocator(uint32_t frameIndex);
    +
    8042  void RecordDestroyAllocator(uint32_t frameIndex);
    +
    8043  void RecordCreatePool(uint32_t frameIndex,
    +
    8044  const VmaPoolCreateInfo& createInfo,
    +
    8045  VmaPool pool);
    +
    8046  void RecordDestroyPool(uint32_t frameIndex, VmaPool pool);
    +
    8047  void RecordAllocateMemory(uint32_t frameIndex,
    8048  const VkMemoryRequirements& vkMemReq,
    -
    8049  bool requiresDedicatedAllocation,
    -
    8050  bool prefersDedicatedAllocation,
    -
    8051  const VmaAllocationCreateInfo& createInfo,
    -
    8052  VmaAllocation allocation);
    -
    8053  void RecordFreeMemory(uint32_t frameIndex,
    -
    8054  VmaAllocation allocation);
    -
    8055  void RecordFreeMemoryPages(uint32_t frameIndex,
    -
    8056  uint64_t allocationCount,
    -
    8057  const VmaAllocation* pAllocations);
    -
    8058  void RecordSetAllocationUserData(uint32_t frameIndex,
    -
    8059  VmaAllocation allocation,
    -
    8060  const void* pUserData);
    -
    8061  void RecordCreateLostAllocation(uint32_t frameIndex,
    -
    8062  VmaAllocation allocation);
    -
    8063  void RecordMapMemory(uint32_t frameIndex,
    -
    8064  VmaAllocation allocation);
    -
    8065  void RecordUnmapMemory(uint32_t frameIndex,
    -
    8066  VmaAllocation allocation);
    -
    8067  void RecordFlushAllocation(uint32_t frameIndex,
    -
    8068  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
    -
    8069  void RecordInvalidateAllocation(uint32_t frameIndex,
    -
    8070  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
    -
    8071  void RecordCreateBuffer(uint32_t frameIndex,
    -
    8072  const VkBufferCreateInfo& bufCreateInfo,
    -
    8073  const VmaAllocationCreateInfo& allocCreateInfo,
    -
    8074  VmaAllocation allocation);
    -
    8075  void RecordCreateImage(uint32_t frameIndex,
    -
    8076  const VkImageCreateInfo& imageCreateInfo,
    -
    8077  const VmaAllocationCreateInfo& allocCreateInfo,
    -
    8078  VmaAllocation allocation);
    -
    8079  void RecordDestroyBuffer(uint32_t frameIndex,
    -
    8080  VmaAllocation allocation);
    -
    8081  void RecordDestroyImage(uint32_t frameIndex,
    -
    8082  VmaAllocation allocation);
    -
    8083  void RecordTouchAllocation(uint32_t frameIndex,
    -
    8084  VmaAllocation allocation);
    -
    8085  void RecordGetAllocationInfo(uint32_t frameIndex,
    -
    8086  VmaAllocation allocation);
    -
    8087  void RecordMakePoolAllocationsLost(uint32_t frameIndex,
    -
    8088  VmaPool pool);
    -
    8089  void RecordDefragmentationBegin(uint32_t frameIndex,
    -
    8090  const VmaDefragmentationInfo2& info,
    -
    8091  VmaDefragmentationContext ctx);
    -
    8092  void RecordDefragmentationEnd(uint32_t frameIndex,
    -
    8093  VmaDefragmentationContext ctx);
    -
    8094  void RecordSetPoolName(uint32_t frameIndex,
    -
    8095  VmaPool pool,
    -
    8096  const char* name);
    -
    8097 
    -
    8098 private:
    -
    8099  struct CallParams
    -
    8100  {
    -
    8101  uint32_t threadId;
    -
    8102  double time;
    -
    8103  };
    -
    8104 
    -
    8105  class UserDataString
    -
    8106  {
    -
    8107  public:
    -
    8108  UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData);
    -
    8109  const char* GetString() const { return m_Str; }
    -
    8110 
    -
    8111  private:
    -
    8112  char m_PtrStr[17];
    -
    8113  const char* m_Str;
    -
    8114  };
    -
    8115 
    -
    8116  bool m_UseMutex;
    -
    8117  VmaRecordFlags m_Flags;
    -
    8118  FILE* m_File;
    -
    8119  VMA_MUTEX m_FileMutex;
    -
    8120  std::chrono::time_point<std::chrono::high_resolution_clock> m_RecordingStartTime;
    -
    8121 
    -
    8122  void GetBasicParams(CallParams& outParams);
    -
    8123 
    -
    8124  // T must be a pointer type, e.g. VmaAllocation, VmaPool.
    -
    8125  template<typename T>
    -
    8126  void PrintPointerList(uint64_t count, const T* pItems)
    -
    8127  {
    -
    8128  if(count)
    -
    8129  {
    -
    8130  fprintf(m_File, "%p", pItems[0]);
    -
    8131  for(uint64_t i = 1; i < count; ++i)
    -
    8132  {
    -
    8133  fprintf(m_File, " %p", pItems[i]);
    -
    8134  }
    -
    8135  }
    -
    8136  }
    -
    8137 
    -
    8138  void PrintPointerList(uint64_t count, const VmaAllocation* pItems);
    -
    8139  void Flush();
    -
    8140 };
    -
    8141 
    -
    8142 #endif // #if VMA_RECORDING_ENABLED
    -
    8143 
    -
    8144 /*
    -
    8145 Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects.
    -
    8146 */
    -
    8147 class VmaAllocationObjectAllocator
    -
    8148 {
    -
    8149  VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator)
    -
    8150 public:
    -
    8151  VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks);
    +
    8049  const VmaAllocationCreateInfo& createInfo,
    +
    8050  VmaAllocation allocation);
    +
    8051  void RecordAllocateMemoryPages(uint32_t frameIndex,
    +
    8052  const VkMemoryRequirements& vkMemReq,
    +
    8053  const VmaAllocationCreateInfo& createInfo,
    +
    8054  uint64_t allocationCount,
    +
    8055  const VmaAllocation* pAllocations);
    +
    8056  void RecordAllocateMemoryForBuffer(uint32_t frameIndex,
    +
    8057  const VkMemoryRequirements& vkMemReq,
    +
    8058  bool requiresDedicatedAllocation,
    +
    8059  bool prefersDedicatedAllocation,
    +
    8060  const VmaAllocationCreateInfo& createInfo,
    +
    8061  VmaAllocation allocation);
    +
    8062  void RecordAllocateMemoryForImage(uint32_t frameIndex,
    +
    8063  const VkMemoryRequirements& vkMemReq,
    +
    8064  bool requiresDedicatedAllocation,
    +
    8065  bool prefersDedicatedAllocation,
    +
    8066  const VmaAllocationCreateInfo& createInfo,
    +
    8067  VmaAllocation allocation);
    +
    8068  void RecordFreeMemory(uint32_t frameIndex,
    +
    8069  VmaAllocation allocation);
    +
    8070  void RecordFreeMemoryPages(uint32_t frameIndex,
    +
    8071  uint64_t allocationCount,
    +
    8072  const VmaAllocation* pAllocations);
    +
    8073  void RecordSetAllocationUserData(uint32_t frameIndex,
    +
    8074  VmaAllocation allocation,
    +
    8075  const void* pUserData);
    +
    8076  void RecordCreateLostAllocation(uint32_t frameIndex,
    +
    8077  VmaAllocation allocation);
    +
    8078  void RecordMapMemory(uint32_t frameIndex,
    +
    8079  VmaAllocation allocation);
    +
    8080  void RecordUnmapMemory(uint32_t frameIndex,
    +
    8081  VmaAllocation allocation);
    +
    8082  void RecordFlushAllocation(uint32_t frameIndex,
    +
    8083  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
    +
    8084  void RecordInvalidateAllocation(uint32_t frameIndex,
    +
    8085  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
    +
    8086  void RecordCreateBuffer(uint32_t frameIndex,
    +
    8087  const VkBufferCreateInfo& bufCreateInfo,
    +
    8088  const VmaAllocationCreateInfo& allocCreateInfo,
    +
    8089  VmaAllocation allocation);
    +
    8090  void RecordCreateImage(uint32_t frameIndex,
    +
    8091  const VkImageCreateInfo& imageCreateInfo,
    +
    8092  const VmaAllocationCreateInfo& allocCreateInfo,
    +
    8093  VmaAllocation allocation);
    +
    8094  void RecordDestroyBuffer(uint32_t frameIndex,
    +
    8095  VmaAllocation allocation);
    +
    8096  void RecordDestroyImage(uint32_t frameIndex,
    +
    8097  VmaAllocation allocation);
    +
    8098  void RecordTouchAllocation(uint32_t frameIndex,
    +
    8099  VmaAllocation allocation);
    +
    8100  void RecordGetAllocationInfo(uint32_t frameIndex,
    +
    8101  VmaAllocation allocation);
    +
    8102  void RecordMakePoolAllocationsLost(uint32_t frameIndex,
    +
    8103  VmaPool pool);
    +
    8104  void RecordDefragmentationBegin(uint32_t frameIndex,
    +
    8105  const VmaDefragmentationInfo2& info,
    +
    8106  VmaDefragmentationContext ctx);
    +
    8107  void RecordDefragmentationEnd(uint32_t frameIndex,
    +
    8108  VmaDefragmentationContext ctx);
    +
    8109  void RecordSetPoolName(uint32_t frameIndex,
    +
    8110  VmaPool pool,
    +
    8111  const char* name);
    +
    8112 
    +
    8113 private:
    +
    8114  struct CallParams
    +
    8115  {
    +
    8116  uint32_t threadId;
    +
    8117  double time;
    +
    8118  };
    +
    8119 
    +
    8120  class UserDataString
    +
    8121  {
    +
    8122  public:
    +
    8123  UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData);
    +
    8124  const char* GetString() const { return m_Str; }
    +
    8125 
    +
    8126  private:
    +
    8127  char m_PtrStr[17];
    +
    8128  const char* m_Str;
    +
    8129  };
    +
    8130 
    +
    8131  bool m_UseMutex;
    +
    8132  VmaRecordFlags m_Flags;
    +
    8133  FILE* m_File;
    +
    8134  VMA_MUTEX m_FileMutex;
    +
    8135  std::chrono::time_point<std::chrono::high_resolution_clock> m_RecordingStartTime;
    +
    8136 
    +
    8137  void GetBasicParams(CallParams& outParams);
    +
    8138 
    +
    8139  // T must be a pointer type, e.g. VmaAllocation, VmaPool.
    +
    8140  template<typename T>
    +
    8141  void PrintPointerList(uint64_t count, const T* pItems)
    +
    8142  {
    +
    8143  if(count)
    +
    8144  {
    +
    8145  fprintf(m_File, "%p", pItems[0]);
    +
    8146  for(uint64_t i = 1; i < count; ++i)
    +
    8147  {
    +
    8148  fprintf(m_File, " %p", pItems[i]);
    +
    8149  }
    +
    8150  }
    +
    8151  }
    8152 
    -
    8153  template<typename... Types> VmaAllocation Allocate(Types... args);
    -
    8154  void Free(VmaAllocation hAlloc);
    -
    8155 
    -
    8156 private:
    -
    8157  VMA_MUTEX m_Mutex;
    -
    8158  VmaPoolAllocator<VmaAllocation_T> m_Allocator;
    -
    8159 };
    -
    8160 
    -
    8161 struct VmaCurrentBudgetData
    -
    8162 {
    -
    8163  VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS];
    -
    8164  VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS];
    -
    8165 
    -
    8166 #if VMA_MEMORY_BUDGET
    -
    8167  VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch;
    -
    8168  VMA_RW_MUTEX m_BudgetMutex;
    -
    8169  uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS];
    -
    8170  uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS];
    -
    8171  uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS];
    -
    8172 #endif // #if VMA_MEMORY_BUDGET
    -
    8173 
    -
    8174  VmaCurrentBudgetData()
    -
    8175  {
    -
    8176  for(uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex)
    -
    8177  {
    -
    8178  m_BlockBytes[heapIndex] = 0;
    -
    8179  m_AllocationBytes[heapIndex] = 0;
    -
    8180 #if VMA_MEMORY_BUDGET
    -
    8181  m_VulkanUsage[heapIndex] = 0;
    -
    8182  m_VulkanBudget[heapIndex] = 0;
    -
    8183  m_BlockBytesAtBudgetFetch[heapIndex] = 0;
    -
    8184 #endif
    -
    8185  }
    -
    8186 
    -
    8187 #if VMA_MEMORY_BUDGET
    -
    8188  m_OperationsSinceBudgetFetch = 0;
    -
    8189 #endif
    -
    8190  }
    -
    8191 
    -
    8192  void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
    -
    8193  {
    -
    8194  m_AllocationBytes[heapIndex] += allocationSize;
    +
    8153  void PrintPointerList(uint64_t count, const VmaAllocation* pItems);
    +
    8154  void Flush();
    +
    8155 };
    +
    8156 
    +
    8157 #endif // #if VMA_RECORDING_ENABLED
    +
    8158 
    +
    8159 /*
    +
    8160 Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects.
    +
    8161 */
    +
    8162 class VmaAllocationObjectAllocator
    +
    8163 {
    +
    8164  VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator)
    +
    8165 public:
    +
    8166  VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks);
    +
    8167 
    +
    8168  template<typename... Types> VmaAllocation Allocate(Types... args);
    +
    8169  void Free(VmaAllocation hAlloc);
    +
    8170 
    +
    8171 private:
    +
    8172  VMA_MUTEX m_Mutex;
    +
    8173  VmaPoolAllocator<VmaAllocation_T> m_Allocator;
    +
    8174 };
    +
    8175 
    +
    8176 struct VmaCurrentBudgetData
    +
    8177 {
    +
    8178  VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS];
    +
    8179  VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS];
    +
    8180 
    +
    8181 #if VMA_MEMORY_BUDGET
    +
    8182  VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch;
    +
    8183  VMA_RW_MUTEX m_BudgetMutex;
    +
    8184  uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS];
    +
    8185  uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS];
    +
    8186  uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS];
    +
    8187 #endif // #if VMA_MEMORY_BUDGET
    +
    8188 
    +
    8189  VmaCurrentBudgetData()
    +
    8190  {
    +
    8191  for(uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex)
    +
    8192  {
    +
    8193  m_BlockBytes[heapIndex] = 0;
    +
    8194  m_AllocationBytes[heapIndex] = 0;
    8195 #if VMA_MEMORY_BUDGET
    -
    8196  ++m_OperationsSinceBudgetFetch;
    -
    8197 #endif
    -
    8198  }
    -
    8199 
    -
    8200  void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
    -
    8201  {
    -
    8202  VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME
    -
    8203  m_AllocationBytes[heapIndex] -= allocationSize;
    -
    8204 #if VMA_MEMORY_BUDGET
    -
    8205  ++m_OperationsSinceBudgetFetch;
    -
    8206 #endif
    -
    8207  }
    -
    8208 };
    -
    8209 
    -
    8210 // Main allocator object.
    -
    8211 struct VmaAllocator_T
    -
    8212 {
    -
    8213  VMA_CLASS_NO_COPY(VmaAllocator_T)
    -
    8214 public:
    -
    8215  bool m_UseMutex;
    -
    8216  uint32_t m_VulkanApiVersion;
    -
    8217  bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
    -
    8218  bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
    -
    8219  bool m_UseExtMemoryBudget;
    -
    8220  bool m_UseAmdDeviceCoherentMemory;
    -
    8221  bool m_UseKhrBufferDeviceAddress;
    -
    8222  bool m_UseExtMemoryPriority;
    -
    8223  VkDevice m_hDevice;
    -
    8224  VkInstance m_hInstance;
    -
    8225  bool m_AllocationCallbacksSpecified;
    -
    8226  VkAllocationCallbacks m_AllocationCallbacks;
    -
    8227  VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
    -
    8228  VmaAllocationObjectAllocator m_AllocationObjectAllocator;
    -
    8229 
    -
    8230  // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size.
    -
    8231  uint32_t m_HeapSizeLimitMask;
    -
    8232 
    -
    8233  VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
    -
    8234  VkPhysicalDeviceMemoryProperties m_MemProps;
    -
    8235 
    -
    8236  // Default pools.
    -
    8237  VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
    -
    8238 
    -
    8239  typedef VmaIntrusiveLinkedList<VmaDedicatedAllocationListItemTraits> DedicatedAllocationLinkedList;
    -
    8240  DedicatedAllocationLinkedList m_DedicatedAllocations[VK_MAX_MEMORY_TYPES];
    -
    8241  VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
    -
    8242 
    -
    8243  VmaCurrentBudgetData m_Budget;
    -
    8244  VMA_ATOMIC_UINT32 m_DeviceMemoryCount; // Total number of VkDeviceMemory objects.
    -
    8245 
    -
    8246  VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
    -
    8247  VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo);
    -
    8248  ~VmaAllocator_T();
    -
    8249 
    -
    8250  const VkAllocationCallbacks* GetAllocationCallbacks() const
    -
    8251  {
    -
    8252  return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
    -
    8253  }
    -
    8254  const VmaVulkanFunctions& GetVulkanFunctions() const
    -
    8255  {
    -
    8256  return m_VulkanFunctions;
    -
    8257  }
    -
    8258 
    -
    8259  VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; }
    +
    8196  m_VulkanUsage[heapIndex] = 0;
    +
    8197  m_VulkanBudget[heapIndex] = 0;
    +
    8198  m_BlockBytesAtBudgetFetch[heapIndex] = 0;
    +
    8199 #endif
    +
    8200  }
    +
    8201 
    +
    8202 #if VMA_MEMORY_BUDGET
    +
    8203  m_OperationsSinceBudgetFetch = 0;
    +
    8204 #endif
    +
    8205  }
    +
    8206 
    +
    8207  void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
    +
    8208  {
    +
    8209  m_AllocationBytes[heapIndex] += allocationSize;
    +
    8210 #if VMA_MEMORY_BUDGET
    +
    8211  ++m_OperationsSinceBudgetFetch;
    +
    8212 #endif
    +
    8213  }
    +
    8214 
    +
    8215  void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
    +
    8216  {
    +
    8217  VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME
    +
    8218  m_AllocationBytes[heapIndex] -= allocationSize;
    +
    8219 #if VMA_MEMORY_BUDGET
    +
    8220  ++m_OperationsSinceBudgetFetch;
    +
    8221 #endif
    +
    8222  }
    +
    8223 };
    +
    8224 
    +
    8225 // Main allocator object.
    +
    8226 struct VmaAllocator_T
    +
    8227 {
    +
    8228  VMA_CLASS_NO_COPY(VmaAllocator_T)
    +
    8229 public:
    +
    8230  bool m_UseMutex;
    +
    8231  uint32_t m_VulkanApiVersion;
    +
    8232  bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
    +
    8233  bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
    +
    8234  bool m_UseExtMemoryBudget;
    +
    8235  bool m_UseAmdDeviceCoherentMemory;
    +
    8236  bool m_UseKhrBufferDeviceAddress;
    +
    8237  bool m_UseExtMemoryPriority;
    +
    8238  VkDevice m_hDevice;
    +
    8239  VkInstance m_hInstance;
    +
    8240  bool m_AllocationCallbacksSpecified;
    +
    8241  VkAllocationCallbacks m_AllocationCallbacks;
    +
    8242  VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
    +
    8243  VmaAllocationObjectAllocator m_AllocationObjectAllocator;
    +
    8244 
    +
    8245  // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size.
    +
    8246  uint32_t m_HeapSizeLimitMask;
    +
    8247 
    +
    8248  VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
    +
    8249  VkPhysicalDeviceMemoryProperties m_MemProps;
    +
    8250 
    +
    8251  // Default pools.
    +
    8252  VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
    +
    8253 
    +
    8254  typedef VmaIntrusiveLinkedList<VmaDedicatedAllocationListItemTraits> DedicatedAllocationLinkedList;
    +
    8255  DedicatedAllocationLinkedList m_DedicatedAllocations[VK_MAX_MEMORY_TYPES];
    +
    8256  VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
    +
    8257 
    +
    8258  VmaCurrentBudgetData m_Budget;
    +
    8259  VMA_ATOMIC_UINT32 m_DeviceMemoryCount; // Total number of VkDeviceMemory objects.
    8260 
    -
    8261  VkDeviceSize GetBufferImageGranularity() const
    -
    8262  {
    -
    8263  return VMA_MAX(
    -
    8264  static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
    -
    8265  m_PhysicalDeviceProperties.limits.bufferImageGranularity);
    -
    8266  }
    -
    8267 
    -
    8268  uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
    -
    8269  uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
    -
    8270 
    -
    8271  uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const
    -
    8272  {
    -
    8273  VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount);
    -
    8274  return m_MemProps.memoryTypes[memTypeIndex].heapIndex;
    -
    8275  }
    -
    8276  // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT.
    -
    8277  bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const
    -
    8278  {
    -
    8279  return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==
    -
    8280  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    +
    8261  VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
    +
    8262  VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo);
    +
    8263  ~VmaAllocator_T();
    +
    8264 
    +
    8265  const VkAllocationCallbacks* GetAllocationCallbacks() const
    +
    8266  {
    +
    8267  return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
    +
    8268  }
    +
    8269  const VmaVulkanFunctions& GetVulkanFunctions() const
    +
    8270  {
    +
    8271  return m_VulkanFunctions;
    +
    8272  }
    +
    8273 
    +
    8274  VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; }
    +
    8275 
    +
    8276  VkDeviceSize GetBufferImageGranularity() const
    +
    8277  {
    +
    8278  return VMA_MAX(
    +
    8279  static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
    +
    8280  m_PhysicalDeviceProperties.limits.bufferImageGranularity);
    8281  }
    -
    8282  // Minimum alignment for all allocations in specific memory type.
    -
    8283  VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const
    -
    8284  {
    -
    8285  return IsMemoryTypeNonCoherent(memTypeIndex) ?
    -
    8286  VMA_MAX((VkDeviceSize)VMA_MIN_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) :
    -
    8287  (VkDeviceSize)VMA_MIN_ALIGNMENT;
    -
    8288  }
    -
    8289 
    -
    8290  bool IsIntegratedGpu() const
    -
    8291  {
    -
    8292  return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
    -
    8293  }
    -
    8294 
    -
    8295  uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; }
    -
    8296 
    -
    8297 #if VMA_RECORDING_ENABLED
    -
    8298  VmaRecorder* GetRecorder() const { return m_pRecorder; }
    -
    8299 #endif
    -
    8300 
    -
    8301  void GetBufferMemoryRequirements(
    -
    8302  VkBuffer hBuffer,
    -
    8303  VkMemoryRequirements& memReq,
    -
    8304  bool& requiresDedicatedAllocation,
    -
    8305  bool& prefersDedicatedAllocation) const;
    -
    8306  void GetImageMemoryRequirements(
    -
    8307  VkImage hImage,
    -
    8308  VkMemoryRequirements& memReq,
    -
    8309  bool& requiresDedicatedAllocation,
    -
    8310  bool& prefersDedicatedAllocation) const;
    +
    8282 
    +
    8283  uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
    +
    8284  uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
    +
    8285 
    +
    8286  uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const
    +
    8287  {
    +
    8288  VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount);
    +
    8289  return m_MemProps.memoryTypes[memTypeIndex].heapIndex;
    +
    8290  }
    +
    8291  // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT.
    +
    8292  bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const
    +
    8293  {
    +
    8294  return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==
    +
    8295  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    +
    8296  }
    +
    8297  // Minimum alignment for all allocations in specific memory type.
    +
    8298  VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const
    +
    8299  {
    +
    8300  return IsMemoryTypeNonCoherent(memTypeIndex) ?
    +
    8301  VMA_MAX((VkDeviceSize)VMA_MIN_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) :
    +
    8302  (VkDeviceSize)VMA_MIN_ALIGNMENT;
    +
    8303  }
    +
    8304 
    +
    8305  bool IsIntegratedGpu() const
    +
    8306  {
    +
    8307  return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
    +
    8308  }
    +
    8309 
    +
    8310  uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; }
    8311 
    -
    8312  // Main allocation function.
    -
    8313  VkResult AllocateMemory(
    -
    8314  const VkMemoryRequirements& vkMemReq,
    -
    8315  bool requiresDedicatedAllocation,
    -
    8316  bool prefersDedicatedAllocation,
    -
    8317  VkBuffer dedicatedBuffer,
    -
    8318  VkBufferUsageFlags dedicatedBufferUsage, // UINT32_MAX when unknown.
    -
    8319  VkImage dedicatedImage,
    -
    8320  const VmaAllocationCreateInfo& createInfo,
    -
    8321  VmaSuballocationType suballocType,
    -
    8322  size_t allocationCount,
    -
    8323  VmaAllocation* pAllocations);
    -
    8324 
    -
    8325  // Main deallocation function.
    -
    8326  void FreeMemory(
    -
    8327  size_t allocationCount,
    -
    8328  const VmaAllocation* pAllocations);
    -
    8329 
    -
    8330  void CalculateStats(VmaStats* pStats);
    -
    8331 
    -
    8332  void GetBudget(
    -
    8333  VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount);
    -
    8334 
    -
    8335 #if VMA_STATS_STRING_ENABLED
    -
    8336  void PrintDetailedMap(class VmaJsonWriter& json);
    -
    8337 #endif
    -
    8338 
    -
    8339  VkResult DefragmentationBegin(
    -
    8340  const VmaDefragmentationInfo2& info,
    -
    8341  VmaDefragmentationStats* pStats,
    -
    8342  VmaDefragmentationContext* pContext);
    -
    8343  VkResult DefragmentationEnd(
    -
    8344  VmaDefragmentationContext context);
    -
    8345 
    -
    8346  VkResult DefragmentationPassBegin(
    -
    8347  VmaDefragmentationPassInfo* pInfo,
    -
    8348  VmaDefragmentationContext context);
    -
    8349  VkResult DefragmentationPassEnd(
    -
    8350  VmaDefragmentationContext context);
    -
    8351 
    -
    8352  void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
    -
    8353  bool TouchAllocation(VmaAllocation hAllocation);
    -
    8354 
    -
    8355  VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool);
    -
    8356  void DestroyPool(VmaPool pool);
    -
    8357  void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats);
    -
    8358 
    -
    8359  void SetCurrentFrameIndex(uint32_t frameIndex);
    -
    8360  uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
    -
    8361 
    -
    8362  void MakePoolAllocationsLost(
    -
    8363  VmaPool hPool,
    -
    8364  size_t* pLostAllocationCount);
    -
    8365  VkResult CheckPoolCorruption(VmaPool hPool);
    -
    8366  VkResult CheckCorruption(uint32_t memoryTypeBits);
    -
    8367 
    -
    8368  void CreateLostAllocation(VmaAllocation* pAllocation);
    +
    8312 #if VMA_RECORDING_ENABLED
    +
    8313  VmaRecorder* GetRecorder() const { return m_pRecorder; }
    +
    8314 #endif
    +
    8315 
    +
    8316  void GetBufferMemoryRequirements(
    +
    8317  VkBuffer hBuffer,
    +
    8318  VkMemoryRequirements& memReq,
    +
    8319  bool& requiresDedicatedAllocation,
    +
    8320  bool& prefersDedicatedAllocation) const;
    +
    8321  void GetImageMemoryRequirements(
    +
    8322  VkImage hImage,
    +
    8323  VkMemoryRequirements& memReq,
    +
    8324  bool& requiresDedicatedAllocation,
    +
    8325  bool& prefersDedicatedAllocation) const;
    +
    8326 
    +
    8327  // Main allocation function.
    +
    8328  VkResult AllocateMemory(
    +
    8329  const VkMemoryRequirements& vkMemReq,
    +
    8330  bool requiresDedicatedAllocation,
    +
    8331  bool prefersDedicatedAllocation,
    +
    8332  VkBuffer dedicatedBuffer,
    +
    8333  VkBufferUsageFlags dedicatedBufferUsage, // UINT32_MAX when unknown.
    +
    8334  VkImage dedicatedImage,
    +
    8335  const VmaAllocationCreateInfo& createInfo,
    +
    8336  VmaSuballocationType suballocType,
    +
    8337  size_t allocationCount,
    +
    8338  VmaAllocation* pAllocations);
    +
    8339 
    +
    8340  // Main deallocation function.
    +
    8341  void FreeMemory(
    +
    8342  size_t allocationCount,
    +
    8343  const VmaAllocation* pAllocations);
    +
    8344 
    +
    8345  void CalculateStats(VmaStats* pStats);
    +
    8346 
    +
    8347  void GetBudget(
    +
    8348  VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount);
    +
    8349 
    +
    8350 #if VMA_STATS_STRING_ENABLED
    +
    8351  void PrintDetailedMap(class VmaJsonWriter& json);
    +
    8352 #endif
    +
    8353 
    +
    8354  VkResult DefragmentationBegin(
    +
    8355  const VmaDefragmentationInfo2& info,
    +
    8356  VmaDefragmentationStats* pStats,
    +
    8357  VmaDefragmentationContext* pContext);
    +
    8358  VkResult DefragmentationEnd(
    +
    8359  VmaDefragmentationContext context);
    +
    8360 
    +
    8361  VkResult DefragmentationPassBegin(
    +
    8362  VmaDefragmentationPassInfo* pInfo,
    +
    8363  VmaDefragmentationContext context);
    +
    8364  VkResult DefragmentationPassEnd(
    +
    8365  VmaDefragmentationContext context);
    +
    8366 
    +
    8367  void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
    +
    8368  bool TouchAllocation(VmaAllocation hAllocation);
    8369 
    -
    8370  // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping.
    -
    8371  VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory);
    -
    8372  // Call to Vulkan function vkFreeMemory with accompanying bookkeeping.
    -
    8373  void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory);
    -
    8374  // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR.
    -
    8375  VkResult BindVulkanBuffer(
    -
    8376  VkDeviceMemory memory,
    -
    8377  VkDeviceSize memoryOffset,
    -
    8378  VkBuffer buffer,
    -
    8379  const void* pNext);
    -
    8380  // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR.
    -
    8381  VkResult BindVulkanImage(
    -
    8382  VkDeviceMemory memory,
    -
    8383  VkDeviceSize memoryOffset,
    -
    8384  VkImage image,
    -
    8385  const void* pNext);
    -
    8386 
    -
    8387  VkResult Map(VmaAllocation hAllocation, void** ppData);
    -
    8388  void Unmap(VmaAllocation hAllocation);
    -
    8389 
    -
    8390  VkResult BindBufferMemory(
    -
    8391  VmaAllocation hAllocation,
    -
    8392  VkDeviceSize allocationLocalOffset,
    -
    8393  VkBuffer hBuffer,
    +
    8370  VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool);
    +
    8371  void DestroyPool(VmaPool pool);
    +
    8372  void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats);
    +
    8373 
    +
    8374  void SetCurrentFrameIndex(uint32_t frameIndex);
    +
    8375  uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
    +
    8376 
    +
    8377  void MakePoolAllocationsLost(
    +
    8378  VmaPool hPool,
    +
    8379  size_t* pLostAllocationCount);
    +
    8380  VkResult CheckPoolCorruption(VmaPool hPool);
    +
    8381  VkResult CheckCorruption(uint32_t memoryTypeBits);
    +
    8382 
    +
    8383  void CreateLostAllocation(VmaAllocation* pAllocation);
    +
    8384 
    +
    8385  // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping.
    +
    8386  VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory);
    +
    8387  // Call to Vulkan function vkFreeMemory with accompanying bookkeeping.
    +
    8388  void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory);
    +
    8389  // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR.
    +
    8390  VkResult BindVulkanBuffer(
    +
    8391  VkDeviceMemory memory,
    +
    8392  VkDeviceSize memoryOffset,
    +
    8393  VkBuffer buffer,
    8394  const void* pNext);
    -
    8395  VkResult BindImageMemory(
    -
    8396  VmaAllocation hAllocation,
    -
    8397  VkDeviceSize allocationLocalOffset,
    -
    8398  VkImage hImage,
    -
    8399  const void* pNext);
    -
    8400 
    -
    8401  VkResult FlushOrInvalidateAllocation(
    -
    8402  VmaAllocation hAllocation,
    -
    8403  VkDeviceSize offset, VkDeviceSize size,
    -
    8404  VMA_CACHE_OPERATION op);
    -
    8405  VkResult FlushOrInvalidateAllocations(
    -
    8406  uint32_t allocationCount,
    -
    8407  const VmaAllocation* allocations,
    -
    8408  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
    -
    8409  VMA_CACHE_OPERATION op);
    -
    8410 
    -
    8411  void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern);
    -
    8412 
    -
    8413  /*
    -
    8414  Returns bit mask of memory types that can support defragmentation on GPU as
    -
    8415  they support creation of required buffer for copy operations.
    -
    8416  */
    -
    8417  uint32_t GetGpuDefragmentationMemoryTypeBits();
    -
    8418 
    -
    8419 #if VMA_EXTERNAL_MEMORY
    -
    8420  VkExternalMemoryHandleTypeFlagsKHR GetExternalMemoryHandleTypeFlags(uint32_t memTypeIndex) const
    -
    8421  {
    -
    8422  return m_TypeExternalMemoryHandleTypes[memTypeIndex];
    -
    8423  }
    -
    8424 #endif // #if VMA_EXTERNAL_MEMORY
    +
    8395  // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR.
    +
    8396  VkResult BindVulkanImage(
    +
    8397  VkDeviceMemory memory,
    +
    8398  VkDeviceSize memoryOffset,
    +
    8399  VkImage image,
    +
    8400  const void* pNext);
    +
    8401 
    +
    8402  VkResult Map(VmaAllocation hAllocation, void** ppData);
    +
    8403  void Unmap(VmaAllocation hAllocation);
    +
    8404 
    +
    8405  VkResult BindBufferMemory(
    +
    8406  VmaAllocation hAllocation,
    +
    8407  VkDeviceSize allocationLocalOffset,
    +
    8408  VkBuffer hBuffer,
    +
    8409  const void* pNext);
    +
    8410  VkResult BindImageMemory(
    +
    8411  VmaAllocation hAllocation,
    +
    8412  VkDeviceSize allocationLocalOffset,
    +
    8413  VkImage hImage,
    +
    8414  const void* pNext);
    +
    8415 
    +
    8416  VkResult FlushOrInvalidateAllocation(
    +
    8417  VmaAllocation hAllocation,
    +
    8418  VkDeviceSize offset, VkDeviceSize size,
    +
    8419  VMA_CACHE_OPERATION op);
    +
    8420  VkResult FlushOrInvalidateAllocations(
    +
    8421  uint32_t allocationCount,
    +
    8422  const VmaAllocation* allocations,
    +
    8423  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
    +
    8424  VMA_CACHE_OPERATION op);
    8425 
    -
    8426 private:
    -
    8427  VkDeviceSize m_PreferredLargeHeapBlockSize;
    -
    8428 
    -
    8429  VkPhysicalDevice m_PhysicalDevice;
    -
    8430  VMA_ATOMIC_UINT32 m_CurrentFrameIndex;
    -
    8431  VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized.
    -
    8432 #if VMA_EXTERNAL_MEMORY
    -
    8433  VkExternalMemoryHandleTypeFlagsKHR m_TypeExternalMemoryHandleTypes[VK_MAX_MEMORY_TYPES];
    -
    8434 #endif // #if VMA_EXTERNAL_MEMORY
    -
    8435 
    -
    8436  VMA_RW_MUTEX m_PoolsMutex;
    -
    8437  typedef VmaIntrusiveLinkedList<VmaPoolListItemTraits> PoolList;
    -
    8438  // Protected by m_PoolsMutex.
    -
    8439  PoolList m_Pools;
    -
    8440  uint32_t m_NextPoolId;
    -
    8441 
    -
    8442  VmaVulkanFunctions m_VulkanFunctions;
    +
    8426  void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern);
    +
    8427 
    +
    8428  /*
    +
    8429  Returns bit mask of memory types that can support defragmentation on GPU as
    +
    8430  they support creation of required buffer for copy operations.
    +
    8431  */
    +
    8432  uint32_t GetGpuDefragmentationMemoryTypeBits();
    +
    8433 
    +
    8434 #if VMA_EXTERNAL_MEMORY
    +
    8435  VkExternalMemoryHandleTypeFlagsKHR GetExternalMemoryHandleTypeFlags(uint32_t memTypeIndex) const
    +
    8436  {
    +
    8437  return m_TypeExternalMemoryHandleTypes[memTypeIndex];
    +
    8438  }
    +
    8439 #endif // #if VMA_EXTERNAL_MEMORY
    +
    8440 
    +
    8441 private:
    +
    8442  VkDeviceSize m_PreferredLargeHeapBlockSize;
    8443 
    -
    8444  // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types.
    -
    8445  uint32_t m_GlobalMemoryTypeBits;
    -
    8446 
    -
    8447 #if VMA_RECORDING_ENABLED
    -
    8448  VmaRecorder* m_pRecorder;
    -
    8449 #endif
    +
    8444  VkPhysicalDevice m_PhysicalDevice;
    +
    8445  VMA_ATOMIC_UINT32 m_CurrentFrameIndex;
    +
    8446  VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized.
    +
    8447 #if VMA_EXTERNAL_MEMORY
    +
    8448  VkExternalMemoryHandleTypeFlagsKHR m_TypeExternalMemoryHandleTypes[VK_MAX_MEMORY_TYPES];
    +
    8449 #endif // #if VMA_EXTERNAL_MEMORY
    8450 
    -
    8451  void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions);
    -
    8452 
    -
    8453 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    -
    8454  void ImportVulkanFunctions_Static();
    -
    8455 #endif
    +
    8451  VMA_RW_MUTEX m_PoolsMutex;
    +
    8452  typedef VmaIntrusiveLinkedList<VmaPoolListItemTraits> PoolList;
    +
    8453  // Protected by m_PoolsMutex.
    +
    8454  PoolList m_Pools;
    +
    8455  uint32_t m_NextPoolId;
    8456 
    -
    8457  void ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions);
    +
    8457  VmaVulkanFunctions m_VulkanFunctions;
    8458 
    -
    8459 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    -
    8460  void ImportVulkanFunctions_Dynamic();
    -
    8461 #endif
    -
    8462 
    -
    8463  void ValidateVulkanFunctions();
    -
    8464 
    -
    8465  VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
    -
    8466 
    -
    8467  VkResult AllocateMemoryOfType(
    -
    8468  VkDeviceSize size,
    -
    8469  VkDeviceSize alignment,
    -
    8470  bool dedicatedAllocation,
    -
    8471  VkBuffer dedicatedBuffer,
    -
    8472  VkBufferUsageFlags dedicatedBufferUsage,
    -
    8473  VkImage dedicatedImage,
    -
    8474  const VmaAllocationCreateInfo& createInfo,
    -
    8475  uint32_t memTypeIndex,
    -
    8476  VmaSuballocationType suballocType,
    -
    8477  size_t allocationCount,
    -
    8478  VmaAllocation* pAllocations);
    +
    8459  // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types.
    +
    8460  uint32_t m_GlobalMemoryTypeBits;
    +
    8461 
    +
    8462 #if VMA_RECORDING_ENABLED
    +
    8463  VmaRecorder* m_pRecorder;
    +
    8464 #endif
    +
    8465 
    +
    8466  void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions);
    +
    8467 
    +
    8468 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    +
    8469  void ImportVulkanFunctions_Static();
    +
    8470 #endif
    +
    8471 
    +
    8472  void ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions);
    +
    8473 
    +
    8474 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    +
    8475  void ImportVulkanFunctions_Dynamic();
    +
    8476 #endif
    +
    8477 
    +
    8478  void ValidateVulkanFunctions();
    8479 
    -
    8480  // Helper function only to be used inside AllocateDedicatedMemory.
    -
    8481  VkResult AllocateDedicatedMemoryPage(
    -
    8482  VkDeviceSize size,
    -
    8483  VmaSuballocationType suballocType,
    -
    8484  uint32_t memTypeIndex,
    -
    8485  const VkMemoryAllocateInfo& allocInfo,
    -
    8486  bool map,
    -
    8487  bool isUserDataString,
    -
    8488  void* pUserData,
    -
    8489  VmaAllocation* pAllocation);
    -
    8490 
    -
    8491  // Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
    -
    8492  VkResult AllocateDedicatedMemory(
    -
    8493  VkDeviceSize size,
    -
    8494  VmaSuballocationType suballocType,
    -
    8495  uint32_t memTypeIndex,
    -
    8496  bool withinBudget,
    -
    8497  bool map,
    -
    8498  bool isUserDataString,
    -
    8499  void* pUserData,
    -
    8500  float priority,
    -
    8501  VkBuffer dedicatedBuffer,
    -
    8502  VkBufferUsageFlags dedicatedBufferUsage,
    -
    8503  VkImage dedicatedImage,
    -
    8504  size_t allocationCount,
    -
    8505  VmaAllocation* pAllocations);
    -
    8506 
    -
    8507  void FreeDedicatedMemory(const VmaAllocation allocation);
    -
    8508 
    -
    8509  /*
    -
    8510  Calculates and returns bit mask of memory types that can support defragmentation
    -
    8511  on GPU as they support creation of required buffer for copy operations.
    -
    8512  */
    -
    8513  uint32_t CalculateGpuDefragmentationMemoryTypeBits() const;
    -
    8514 
    -
    8515  uint32_t CalculateGlobalMemoryTypeBits() const;
    -
    8516 
    -
    8517  bool GetFlushOrInvalidateRange(
    -
    8518  VmaAllocation allocation,
    -
    8519  VkDeviceSize offset, VkDeviceSize size,
    -
    8520  VkMappedMemoryRange& outRange) const;
    +
    8480  VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
    +
    8481 
    +
    8482  VkResult AllocateMemoryOfType(
    +
    8483  VkDeviceSize size,
    +
    8484  VkDeviceSize alignment,
    +
    8485  bool dedicatedAllocation,
    +
    8486  VkBuffer dedicatedBuffer,
    +
    8487  VkBufferUsageFlags dedicatedBufferUsage,
    +
    8488  VkImage dedicatedImage,
    +
    8489  const VmaAllocationCreateInfo& createInfo,
    +
    8490  uint32_t memTypeIndex,
    +
    8491  VmaSuballocationType suballocType,
    +
    8492  size_t allocationCount,
    +
    8493  VmaAllocation* pAllocations);
    +
    8494 
    +
    8495  // Helper function only to be used inside AllocateDedicatedMemory.
    +
    8496  VkResult AllocateDedicatedMemoryPage(
    +
    8497  VkDeviceSize size,
    +
    8498  VmaSuballocationType suballocType,
    +
    8499  uint32_t memTypeIndex,
    +
    8500  const VkMemoryAllocateInfo& allocInfo,
    +
    8501  bool map,
    +
    8502  bool isUserDataString,
    +
    8503  void* pUserData,
    +
    8504  VmaAllocation* pAllocation);
    +
    8505 
    +
    8506  // Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
    +
    8507  VkResult AllocateDedicatedMemory(
    +
    8508  VkDeviceSize size,
    +
    8509  VmaSuballocationType suballocType,
    +
    8510  uint32_t memTypeIndex,
    +
    8511  bool withinBudget,
    +
    8512  bool map,
    +
    8513  bool isUserDataString,
    +
    8514  void* pUserData,
    +
    8515  float priority,
    +
    8516  VkBuffer dedicatedBuffer,
    +
    8517  VkBufferUsageFlags dedicatedBufferUsage,
    +
    8518  VkImage dedicatedImage,
    +
    8519  size_t allocationCount,
    +
    8520  VmaAllocation* pAllocations);
    8521 
    -
    8522 #if VMA_MEMORY_BUDGET
    -
    8523  void UpdateVulkanBudget();
    -
    8524 #endif // #if VMA_MEMORY_BUDGET
    -
    8525 };
    -
    8526 
    -
    8528 // Memory allocation #2 after VmaAllocator_T definition
    +
    8522  void FreeDedicatedMemory(const VmaAllocation allocation);
    +
    8523 
    +
    8524  /*
    +
    8525  Calculates and returns bit mask of memory types that can support defragmentation
    +
    8526  on GPU as they support creation of required buffer for copy operations.
    +
    8527  */
    +
    8528  uint32_t CalculateGpuDefragmentationMemoryTypeBits() const;
    8529 
    -
    8530 static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
    -
    8531 {
    -
    8532  return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
    -
    8533 }
    -
    8534 
    -
    8535 static void VmaFree(VmaAllocator hAllocator, void* ptr)
    -
    8536 {
    -
    8537  VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
    -
    8538 }
    -
    8539 
    -
    8540 template<typename T>
    -
    8541 static T* VmaAllocate(VmaAllocator hAllocator)
    -
    8542 {
    -
    8543  return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
    -
    8544 }
    -
    8545 
    -
    8546 template<typename T>
    -
    8547 static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
    -
    8548 {
    -
    8549  return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
    -
    8550 }
    -
    8551 
    -
    8552 template<typename T>
    -
    8553 static void vma_delete(VmaAllocator hAllocator, T* ptr)
    -
    8554 {
    -
    8555  if(ptr != VMA_NULL)
    -
    8556  {
    -
    8557  ptr->~T();
    -
    8558  VmaFree(hAllocator, ptr);
    -
    8559  }
    -
    8560 }
    -
    8561 
    -
    8562 template<typename T>
    -
    8563 static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
    -
    8564 {
    -
    8565  if(ptr != VMA_NULL)
    -
    8566  {
    -
    8567  for(size_t i = count; i--; )
    -
    8568  ptr[i].~T();
    -
    8569  VmaFree(hAllocator, ptr);
    -
    8570  }
    -
    8571 }
    -
    8572 
    -
    8574 // VmaStringBuilder
    -
    8575 
    -
    8576 #if VMA_STATS_STRING_ENABLED
    -
    8577 
    -
    8578 class VmaStringBuilder
    +
    8530  uint32_t CalculateGlobalMemoryTypeBits() const;
    +
    8531 
    +
    8532  bool GetFlushOrInvalidateRange(
    +
    8533  VmaAllocation allocation,
    +
    8534  VkDeviceSize offset, VkDeviceSize size,
    +
    8535  VkMappedMemoryRange& outRange) const;
    +
    8536 
    +
    8537 #if VMA_MEMORY_BUDGET
    +
    8538  void UpdateVulkanBudget();
    +
    8539 #endif // #if VMA_MEMORY_BUDGET
    +
    8540 };
    +
    8541 
    +
    8543 // Memory allocation #2 after VmaAllocator_T definition
    +
    8544 
    +
    8545 static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
    +
    8546 {
    +
    8547  return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
    +
    8548 }
    +
    8549 
    +
    8550 static void VmaFree(VmaAllocator hAllocator, void* ptr)
    +
    8551 {
    +
    8552  VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
    +
    8553 }
    +
    8554 
    +
    8555 template<typename T>
    +
    8556 static T* VmaAllocate(VmaAllocator hAllocator)
    +
    8557 {
    +
    8558  return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
    +
    8559 }
    +
    8560 
    +
    8561 template<typename T>
    +
    8562 static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
    +
    8563 {
    +
    8564  return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
    +
    8565 }
    +
    8566 
    +
    8567 template<typename T>
    +
    8568 static void vma_delete(VmaAllocator hAllocator, T* ptr)
    +
    8569 {
    +
    8570  if(ptr != VMA_NULL)
    +
    8571  {
    +
    8572  ptr->~T();
    +
    8573  VmaFree(hAllocator, ptr);
    +
    8574  }
    +
    8575 }
    +
    8576 
    +
    8577 template<typename T>
    +
    8578 static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
    8579 {
    -
    8580 public:
    -
    8581  VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
    -
    8582  size_t GetLength() const { return m_Data.size(); }
    -
    8583  const char* GetData() const { return m_Data.data(); }
    -
    8584 
    -
    8585  void Add(char ch) { m_Data.push_back(ch); }
    -
    8586  void Add(const char* pStr);
    -
    8587  void AddNewLine() { Add('\n'); }
    -
    8588  void AddNumber(uint32_t num);
    -
    8589  void AddNumber(uint64_t num);
    -
    8590  void AddPointer(const void* ptr);
    -
    8591 
    -
    8592 private:
    -
    8593  VmaVector< char, VmaStlAllocator<char> > m_Data;
    -
    8594 };
    -
    8595 
    -
    8596 void VmaStringBuilder::Add(const char* pStr)
    -
    8597 {
    -
    8598  const size_t strLen = strlen(pStr);
    -
    8599  if(strLen > 0)
    -
    8600  {
    -
    8601  const size_t oldCount = m_Data.size();
    -
    8602  m_Data.resize(oldCount + strLen);
    -
    8603  memcpy(m_Data.data() + oldCount, pStr, strLen);
    -
    8604  }
    -
    8605 }
    +
    8580  if(ptr != VMA_NULL)
    +
    8581  {
    +
    8582  for(size_t i = count; i--; )
    +
    8583  ptr[i].~T();
    +
    8584  VmaFree(hAllocator, ptr);
    +
    8585  }
    +
    8586 }
    +
    8587 
    +
    8589 // VmaStringBuilder
    +
    8590 
    +
    8591 #if VMA_STATS_STRING_ENABLED
    +
    8592 
    +
    8593 class VmaStringBuilder
    +
    8594 {
    +
    8595 public:
    +
    8596  VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
    +
    8597  size_t GetLength() const { return m_Data.size(); }
    +
    8598  const char* GetData() const { return m_Data.data(); }
    +
    8599 
    +
    8600  void Add(char ch) { m_Data.push_back(ch); }
    +
    8601  void Add(const char* pStr);
    +
    8602  void AddNewLine() { Add('\n'); }
    +
    8603  void AddNumber(uint32_t num);
    +
    8604  void AddNumber(uint64_t num);
    +
    8605  void AddPointer(const void* ptr);
    8606 
    -
    8607 void VmaStringBuilder::AddNumber(uint32_t num)
    -
    8608 {
    -
    8609  char buf[11];
    -
    8610  buf[10] = '\0';
    -
    8611  char *p = &buf[10];
    -
    8612  do
    -
    8613  {
    -
    8614  *--p = '0' + (num % 10);
    -
    8615  num /= 10;
    -
    8616  }
    -
    8617  while(num);
    -
    8618  Add(p);
    -
    8619 }
    -
    8620 
    -
    8621 void VmaStringBuilder::AddNumber(uint64_t num)
    -
    8622 {
    -
    8623  char buf[21];
    -
    8624  buf[20] = '\0';
    -
    8625  char *p = &buf[20];
    -
    8626  do
    -
    8627  {
    -
    8628  *--p = '0' + (num % 10);
    -
    8629  num /= 10;
    -
    8630  }
    -
    8631  while(num);
    -
    8632  Add(p);
    -
    8633 }
    -
    8634 
    -
    8635 void VmaStringBuilder::AddPointer(const void* ptr)
    -
    8636 {
    -
    8637  char buf[21];
    -
    8638  VmaPtrToStr(buf, sizeof(buf), ptr);
    -
    8639  Add(buf);
    -
    8640 }
    -
    8641 
    -
    8642 #endif // #if VMA_STATS_STRING_ENABLED
    -
    8643 
    -
    8645 // VmaJsonWriter
    -
    8646 
    -
    8647 #if VMA_STATS_STRING_ENABLED
    -
    8648 
    -
    8649 class VmaJsonWriter
    -
    8650 {
    -
    8651  VMA_CLASS_NO_COPY(VmaJsonWriter)
    -
    8652 public:
    -
    8653  VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb);
    -
    8654  ~VmaJsonWriter();
    -
    8655 
    -
    8656  void BeginObject(bool singleLine = false);
    -
    8657  void EndObject();
    +
    8607 private:
    +
    8608  VmaVector< char, VmaStlAllocator<char> > m_Data;
    +
    8609 };
    +
    8610 
    +
    8611 void VmaStringBuilder::Add(const char* pStr)
    +
    8612 {
    +
    8613  const size_t strLen = strlen(pStr);
    +
    8614  if(strLen > 0)
    +
    8615  {
    +
    8616  const size_t oldCount = m_Data.size();
    +
    8617  m_Data.resize(oldCount + strLen);
    +
    8618  memcpy(m_Data.data() + oldCount, pStr, strLen);
    +
    8619  }
    +
    8620 }
    +
    8621 
    +
    8622 void VmaStringBuilder::AddNumber(uint32_t num)
    +
    8623 {
    +
    8624  char buf[11];
    +
    8625  buf[10] = '\0';
    +
    8626  char *p = &buf[10];
    +
    8627  do
    +
    8628  {
    +
    8629  *--p = '0' + (num % 10);
    +
    8630  num /= 10;
    +
    8631  }
    +
    8632  while(num);
    +
    8633  Add(p);
    +
    8634 }
    +
    8635 
    +
    8636 void VmaStringBuilder::AddNumber(uint64_t num)
    +
    8637 {
    +
    8638  char buf[21];
    +
    8639  buf[20] = '\0';
    +
    8640  char *p = &buf[20];
    +
    8641  do
    +
    8642  {
    +
    8643  *--p = '0' + (num % 10);
    +
    8644  num /= 10;
    +
    8645  }
    +
    8646  while(num);
    +
    8647  Add(p);
    +
    8648 }
    +
    8649 
    +
    8650 void VmaStringBuilder::AddPointer(const void* ptr)
    +
    8651 {
    +
    8652  char buf[21];
    +
    8653  VmaPtrToStr(buf, sizeof(buf), ptr);
    +
    8654  Add(buf);
    +
    8655 }
    +
    8656 
    +
    8657 #endif // #if VMA_STATS_STRING_ENABLED
    8658 
    -
    8659  void BeginArray(bool singleLine = false);
    -
    8660  void EndArray();
    +
    8660 // VmaJsonWriter
    8661 
    -
    8662  void WriteString(const char* pStr);
    -
    8663  void BeginString(const char* pStr = VMA_NULL);
    -
    8664  void ContinueString(const char* pStr);
    -
    8665  void ContinueString(uint32_t n);
    -
    8666  void ContinueString(uint64_t n);
    -
    8667  void ContinueString_Pointer(const void* ptr);
    -
    8668  void EndString(const char* pStr = VMA_NULL);
    -
    8669 
    -
    8670  void WriteNumber(uint32_t n);
    -
    8671  void WriteNumber(uint64_t n);
    -
    8672  void WriteBool(bool b);
    -
    8673  void WriteNull();
    -
    8674 
    -
    8675 private:
    -
    8676  static const char* const INDENT;
    -
    8677 
    -
    8678  enum COLLECTION_TYPE
    -
    8679  {
    -
    8680  COLLECTION_TYPE_OBJECT,
    -
    8681  COLLECTION_TYPE_ARRAY,
    -
    8682  };
    -
    8683  struct StackItem
    -
    8684  {
    -
    8685  COLLECTION_TYPE type;
    -
    8686  uint32_t valueCount;
    -
    8687  bool singleLineMode;
    -
    8688  };
    +
    8662 #if VMA_STATS_STRING_ENABLED
    +
    8663 
    +
    8664 class VmaJsonWriter
    +
    8665 {
    +
    8666  VMA_CLASS_NO_COPY(VmaJsonWriter)
    +
    8667 public:
    +
    8668  VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb);
    +
    8669  ~VmaJsonWriter();
    +
    8670 
    +
    8671  void BeginObject(bool singleLine = false);
    +
    8672  void EndObject();
    +
    8673 
    +
    8674  void BeginArray(bool singleLine = false);
    +
    8675  void EndArray();
    +
    8676 
    +
    8677  void WriteString(const char* pStr);
    +
    8678  void BeginString(const char* pStr = VMA_NULL);
    +
    8679  void ContinueString(const char* pStr);
    +
    8680  void ContinueString(uint32_t n);
    +
    8681  void ContinueString(uint64_t n);
    +
    8682  void ContinueString_Pointer(const void* ptr);
    +
    8683  void EndString(const char* pStr = VMA_NULL);
    +
    8684 
    +
    8685  void WriteNumber(uint32_t n);
    +
    8686  void WriteNumber(uint64_t n);
    +
    8687  void WriteBool(bool b);
    +
    8688  void WriteNull();
    8689 
    -
    8690  VmaStringBuilder& m_SB;
    -
    8691  VmaVector< StackItem, VmaStlAllocator<StackItem> > m_Stack;
    -
    8692  bool m_InsideString;
    -
    8693 
    -
    8694  void BeginValue(bool isString);
    -
    8695  void WriteIndent(bool oneLess = false);
    -
    8696 };
    -
    8697 
    -
    8698 const char* const VmaJsonWriter::INDENT = " ";
    -
    8699 
    -
    8700 VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) :
    -
    8701  m_SB(sb),
    -
    8702  m_Stack(VmaStlAllocator<StackItem>(pAllocationCallbacks)),
    -
    8703  m_InsideString(false)
    -
    8704 {
    -
    8705 }
    -
    8706 
    -
    8707 VmaJsonWriter::~VmaJsonWriter()
    -
    8708 {
    -
    8709  VMA_ASSERT(!m_InsideString);
    -
    8710  VMA_ASSERT(m_Stack.empty());
    -
    8711 }
    +
    8690 private:
    +
    8691  static const char* const INDENT;
    +
    8692 
    +
    8693  enum COLLECTION_TYPE
    +
    8694  {
    +
    8695  COLLECTION_TYPE_OBJECT,
    +
    8696  COLLECTION_TYPE_ARRAY,
    +
    8697  };
    +
    8698  struct StackItem
    +
    8699  {
    +
    8700  COLLECTION_TYPE type;
    +
    8701  uint32_t valueCount;
    +
    8702  bool singleLineMode;
    +
    8703  };
    +
    8704 
    +
    8705  VmaStringBuilder& m_SB;
    +
    8706  VmaVector< StackItem, VmaStlAllocator<StackItem> > m_Stack;
    +
    8707  bool m_InsideString;
    +
    8708 
    +
    8709  void BeginValue(bool isString);
    +
    8710  void WriteIndent(bool oneLess = false);
    +
    8711 };
    8712 
    -
    8713 void VmaJsonWriter::BeginObject(bool singleLine)
    -
    8714 {
    -
    8715  VMA_ASSERT(!m_InsideString);
    -
    8716 
    -
    8717  BeginValue(false);
    -
    8718  m_SB.Add('{');
    -
    8719 
    -
    8720  StackItem item;
    -
    8721  item.type = COLLECTION_TYPE_OBJECT;
    -
    8722  item.valueCount = 0;
    -
    8723  item.singleLineMode = singleLine;
    -
    8724  m_Stack.push_back(item);
    -
    8725 }
    -
    8726 
    -
    8727 void VmaJsonWriter::EndObject()
    -
    8728 {
    -
    8729  VMA_ASSERT(!m_InsideString);
    -
    8730 
    -
    8731  WriteIndent(true);
    -
    8732  m_SB.Add('}');
    -
    8733 
    -
    8734  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
    -
    8735  m_Stack.pop_back();
    -
    8736 }
    -
    8737 
    -
    8738 void VmaJsonWriter::BeginArray(bool singleLine)
    -
    8739 {
    -
    8740  VMA_ASSERT(!m_InsideString);
    +
    8713 const char* const VmaJsonWriter::INDENT = " ";
    +
    8714 
    +
    8715 VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) :
    +
    8716  m_SB(sb),
    +
    8717  m_Stack(VmaStlAllocator<StackItem>(pAllocationCallbacks)),
    +
    8718  m_InsideString(false)
    +
    8719 {
    +
    8720 }
    +
    8721 
    +
    8722 VmaJsonWriter::~VmaJsonWriter()
    +
    8723 {
    +
    8724  VMA_ASSERT(!m_InsideString);
    +
    8725  VMA_ASSERT(m_Stack.empty());
    +
    8726 }
    +
    8727 
    +
    8728 void VmaJsonWriter::BeginObject(bool singleLine)
    +
    8729 {
    +
    8730  VMA_ASSERT(!m_InsideString);
    +
    8731 
    +
    8732  BeginValue(false);
    +
    8733  m_SB.Add('{');
    +
    8734 
    +
    8735  StackItem item;
    +
    8736  item.type = COLLECTION_TYPE_OBJECT;
    +
    8737  item.valueCount = 0;
    +
    8738  item.singleLineMode = singleLine;
    +
    8739  m_Stack.push_back(item);
    +
    8740 }
    8741 
    -
    8742  BeginValue(false);
    -
    8743  m_SB.Add('[');
    -
    8744 
    -
    8745  StackItem item;
    -
    8746  item.type = COLLECTION_TYPE_ARRAY;
    -
    8747  item.valueCount = 0;
    -
    8748  item.singleLineMode = singleLine;
    -
    8749  m_Stack.push_back(item);
    -
    8750 }
    -
    8751 
    -
    8752 void VmaJsonWriter::EndArray()
    -
    8753 {
    -
    8754  VMA_ASSERT(!m_InsideString);
    -
    8755 
    -
    8756  WriteIndent(true);
    -
    8757  m_SB.Add(']');
    -
    8758 
    -
    8759  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
    -
    8760  m_Stack.pop_back();
    -
    8761 }
    -
    8762 
    -
    8763 void VmaJsonWriter::WriteString(const char* pStr)
    -
    8764 {
    -
    8765  BeginString(pStr);
    -
    8766  EndString();
    -
    8767 }
    -
    8768 
    -
    8769 void VmaJsonWriter::BeginString(const char* pStr)
    -
    8770 {
    -
    8771  VMA_ASSERT(!m_InsideString);
    -
    8772 
    -
    8773  BeginValue(true);
    -
    8774  m_SB.Add('"');
    -
    8775  m_InsideString = true;
    -
    8776  if(pStr != VMA_NULL && pStr[0] != '\0')
    -
    8777  {
    -
    8778  ContinueString(pStr);
    -
    8779  }
    -
    8780 }
    -
    8781 
    -
    8782 void VmaJsonWriter::ContinueString(const char* pStr)
    -
    8783 {
    -
    8784  VMA_ASSERT(m_InsideString);
    -
    8785 
    -
    8786  const size_t strLen = strlen(pStr);
    -
    8787  for(size_t i = 0; i < strLen; ++i)
    -
    8788  {
    -
    8789  char ch = pStr[i];
    -
    8790  if(ch == '\\')
    -
    8791  {
    -
    8792  m_SB.Add("\\\\");
    -
    8793  }
    -
    8794  else if(ch == '"')
    -
    8795  {
    -
    8796  m_SB.Add("\\\"");
    -
    8797  }
    -
    8798  else if(ch >= 32)
    -
    8799  {
    -
    8800  m_SB.Add(ch);
    -
    8801  }
    -
    8802  else switch(ch)
    -
    8803  {
    -
    8804  case '\b':
    -
    8805  m_SB.Add("\\b");
    -
    8806  break;
    -
    8807  case '\f':
    -
    8808  m_SB.Add("\\f");
    -
    8809  break;
    -
    8810  case '\n':
    -
    8811  m_SB.Add("\\n");
    -
    8812  break;
    -
    8813  case '\r':
    -
    8814  m_SB.Add("\\r");
    -
    8815  break;
    -
    8816  case '\t':
    -
    8817  m_SB.Add("\\t");
    -
    8818  break;
    -
    8819  default:
    -
    8820  VMA_ASSERT(0 && "Character not currently supported.");
    +
    8742 void VmaJsonWriter::EndObject()
    +
    8743 {
    +
    8744  VMA_ASSERT(!m_InsideString);
    +
    8745 
    +
    8746  WriteIndent(true);
    +
    8747  m_SB.Add('}');
    +
    8748 
    +
    8749  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
    +
    8750  m_Stack.pop_back();
    +
    8751 }
    +
    8752 
    +
    8753 void VmaJsonWriter::BeginArray(bool singleLine)
    +
    8754 {
    +
    8755  VMA_ASSERT(!m_InsideString);
    +
    8756 
    +
    8757  BeginValue(false);
    +
    8758  m_SB.Add('[');
    +
    8759 
    +
    8760  StackItem item;
    +
    8761  item.type = COLLECTION_TYPE_ARRAY;
    +
    8762  item.valueCount = 0;
    +
    8763  item.singleLineMode = singleLine;
    +
    8764  m_Stack.push_back(item);
    +
    8765 }
    +
    8766 
    +
    8767 void VmaJsonWriter::EndArray()
    +
    8768 {
    +
    8769  VMA_ASSERT(!m_InsideString);
    +
    8770 
    +
    8771  WriteIndent(true);
    +
    8772  m_SB.Add(']');
    +
    8773 
    +
    8774  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
    +
    8775  m_Stack.pop_back();
    +
    8776 }
    +
    8777 
    +
    8778 void VmaJsonWriter::WriteString(const char* pStr)
    +
    8779 {
    +
    8780  BeginString(pStr);
    +
    8781  EndString();
    +
    8782 }
    +
    8783 
    +
    8784 void VmaJsonWriter::BeginString(const char* pStr)
    +
    8785 {
    +
    8786  VMA_ASSERT(!m_InsideString);
    +
    8787 
    +
    8788  BeginValue(true);
    +
    8789  m_SB.Add('"');
    +
    8790  m_InsideString = true;
    +
    8791  if(pStr != VMA_NULL && pStr[0] != '\0')
    +
    8792  {
    +
    8793  ContinueString(pStr);
    +
    8794  }
    +
    8795 }
    +
    8796 
    +
    8797 void VmaJsonWriter::ContinueString(const char* pStr)
    +
    8798 {
    +
    8799  VMA_ASSERT(m_InsideString);
    +
    8800 
    +
    8801  const size_t strLen = strlen(pStr);
    +
    8802  for(size_t i = 0; i < strLen; ++i)
    +
    8803  {
    +
    8804  char ch = pStr[i];
    +
    8805  if(ch == '\\')
    +
    8806  {
    +
    8807  m_SB.Add("\\\\");
    +
    8808  }
    +
    8809  else if(ch == '"')
    +
    8810  {
    +
    8811  m_SB.Add("\\\"");
    +
    8812  }
    +
    8813  else if(ch >= 32)
    +
    8814  {
    +
    8815  m_SB.Add(ch);
    +
    8816  }
    +
    8817  else switch(ch)
    +
    8818  {
    +
    8819  case '\b':
    +
    8820  m_SB.Add("\\b");
    8821  break;
    -
    8822  }
    -
    8823  }
    -
    8824 }
    -
    8825 
    -
    8826 void VmaJsonWriter::ContinueString(uint32_t n)
    -
    8827 {
    -
    8828  VMA_ASSERT(m_InsideString);
    -
    8829  m_SB.AddNumber(n);
    -
    8830 }
    -
    8831 
    -
    8832 void VmaJsonWriter::ContinueString(uint64_t n)
    -
    8833 {
    -
    8834  VMA_ASSERT(m_InsideString);
    -
    8835  m_SB.AddNumber(n);
    -
    8836 }
    -
    8837 
    -
    8838 void VmaJsonWriter::ContinueString_Pointer(const void* ptr)
    -
    8839 {
    -
    8840  VMA_ASSERT(m_InsideString);
    -
    8841  m_SB.AddPointer(ptr);
    -
    8842 }
    -
    8843 
    -
    8844 void VmaJsonWriter::EndString(const char* pStr)
    -
    8845 {
    -
    8846  VMA_ASSERT(m_InsideString);
    -
    8847  if(pStr != VMA_NULL && pStr[0] != '\0')
    -
    8848  {
    -
    8849  ContinueString(pStr);
    -
    8850  }
    -
    8851  m_SB.Add('"');
    -
    8852  m_InsideString = false;
    -
    8853 }
    -
    8854 
    -
    8855 void VmaJsonWriter::WriteNumber(uint32_t n)
    -
    8856 {
    -
    8857  VMA_ASSERT(!m_InsideString);
    -
    8858  BeginValue(false);
    -
    8859  m_SB.AddNumber(n);
    -
    8860 }
    -
    8861 
    -
    8862 void VmaJsonWriter::WriteNumber(uint64_t n)
    -
    8863 {
    -
    8864  VMA_ASSERT(!m_InsideString);
    -
    8865  BeginValue(false);
    -
    8866  m_SB.AddNumber(n);
    -
    8867 }
    -
    8868 
    -
    8869 void VmaJsonWriter::WriteBool(bool b)
    -
    8870 {
    -
    8871  VMA_ASSERT(!m_InsideString);
    -
    8872  BeginValue(false);
    -
    8873  m_SB.Add(b ? "true" : "false");
    -
    8874 }
    -
    8875 
    -
    8876 void VmaJsonWriter::WriteNull()
    -
    8877 {
    -
    8878  VMA_ASSERT(!m_InsideString);
    -
    8879  BeginValue(false);
    -
    8880  m_SB.Add("null");
    -
    8881 }
    -
    8882 
    -
    8883 void VmaJsonWriter::BeginValue(bool isString)
    -
    8884 {
    -
    8885  if(!m_Stack.empty())
    -
    8886  {
    -
    8887  StackItem& currItem = m_Stack.back();
    -
    8888  if(currItem.type == COLLECTION_TYPE_OBJECT &&
    -
    8889  currItem.valueCount % 2 == 0)
    -
    8890  {
    -
    8891  VMA_ASSERT(isString);
    -
    8892  }
    -
    8893 
    -
    8894  if(currItem.type == COLLECTION_TYPE_OBJECT &&
    -
    8895  currItem.valueCount % 2 != 0)
    -
    8896  {
    -
    8897  m_SB.Add(": ");
    -
    8898  }
    -
    8899  else if(currItem.valueCount > 0)
    -
    8900  {
    -
    8901  m_SB.Add(", ");
    -
    8902  WriteIndent();
    -
    8903  }
    -
    8904  else
    +
    8822  case '\f':
    +
    8823  m_SB.Add("\\f");
    +
    8824  break;
    +
    8825  case '\n':
    +
    8826  m_SB.Add("\\n");
    +
    8827  break;
    +
    8828  case '\r':
    +
    8829  m_SB.Add("\\r");
    +
    8830  break;
    +
    8831  case '\t':
    +
    8832  m_SB.Add("\\t");
    +
    8833  break;
    +
    8834  default:
    +
    8835  VMA_ASSERT(0 && "Character not currently supported.");
    +
    8836  break;
    +
    8837  }
    +
    8838  }
    +
    8839 }
    +
    8840 
    +
    8841 void VmaJsonWriter::ContinueString(uint32_t n)
    +
    8842 {
    +
    8843  VMA_ASSERT(m_InsideString);
    +
    8844  m_SB.AddNumber(n);
    +
    8845 }
    +
    8846 
    +
    8847 void VmaJsonWriter::ContinueString(uint64_t n)
    +
    8848 {
    +
    8849  VMA_ASSERT(m_InsideString);
    +
    8850  m_SB.AddNumber(n);
    +
    8851 }
    +
    8852 
    +
    8853 void VmaJsonWriter::ContinueString_Pointer(const void* ptr)
    +
    8854 {
    +
    8855  VMA_ASSERT(m_InsideString);
    +
    8856  m_SB.AddPointer(ptr);
    +
    8857 }
    +
    8858 
    +
    8859 void VmaJsonWriter::EndString(const char* pStr)
    +
    8860 {
    +
    8861  VMA_ASSERT(m_InsideString);
    +
    8862  if(pStr != VMA_NULL && pStr[0] != '\0')
    +
    8863  {
    +
    8864  ContinueString(pStr);
    +
    8865  }
    +
    8866  m_SB.Add('"');
    +
    8867  m_InsideString = false;
    +
    8868 }
    +
    8869 
    +
    8870 void VmaJsonWriter::WriteNumber(uint32_t n)
    +
    8871 {
    +
    8872  VMA_ASSERT(!m_InsideString);
    +
    8873  BeginValue(false);
    +
    8874  m_SB.AddNumber(n);
    +
    8875 }
    +
    8876 
    +
    8877 void VmaJsonWriter::WriteNumber(uint64_t n)
    +
    8878 {
    +
    8879  VMA_ASSERT(!m_InsideString);
    +
    8880  BeginValue(false);
    +
    8881  m_SB.AddNumber(n);
    +
    8882 }
    +
    8883 
    +
    8884 void VmaJsonWriter::WriteBool(bool b)
    +
    8885 {
    +
    8886  VMA_ASSERT(!m_InsideString);
    +
    8887  BeginValue(false);
    +
    8888  m_SB.Add(b ? "true" : "false");
    +
    8889 }
    +
    8890 
    +
    8891 void VmaJsonWriter::WriteNull()
    +
    8892 {
    +
    8893  VMA_ASSERT(!m_InsideString);
    +
    8894  BeginValue(false);
    +
    8895  m_SB.Add("null");
    +
    8896 }
    +
    8897 
    +
    8898 void VmaJsonWriter::BeginValue(bool isString)
    +
    8899 {
    +
    8900  if(!m_Stack.empty())
    +
    8901  {
    +
    8902  StackItem& currItem = m_Stack.back();
    +
    8903  if(currItem.type == COLLECTION_TYPE_OBJECT &&
    +
    8904  currItem.valueCount % 2 == 0)
    8905  {
    -
    8906  WriteIndent();
    +
    8906  VMA_ASSERT(isString);
    8907  }
    -
    8908  ++currItem.valueCount;
    -
    8909  }
    -
    8910 }
    -
    8911 
    -
    8912 void VmaJsonWriter::WriteIndent(bool oneLess)
    -
    8913 {
    -
    8914  if(!m_Stack.empty() && !m_Stack.back().singleLineMode)
    -
    8915  {
    -
    8916  m_SB.AddNewLine();
    -
    8917 
    -
    8918  size_t count = m_Stack.size();
    -
    8919  if(count > 0 && oneLess)
    +
    8908 
    +
    8909  if(currItem.type == COLLECTION_TYPE_OBJECT &&
    +
    8910  currItem.valueCount % 2 != 0)
    +
    8911  {
    +
    8912  m_SB.Add(": ");
    +
    8913  }
    +
    8914  else if(currItem.valueCount > 0)
    +
    8915  {
    +
    8916  m_SB.Add(", ");
    +
    8917  WriteIndent();
    +
    8918  }
    +
    8919  else
    8920  {
    -
    8921  --count;
    +
    8921  WriteIndent();
    8922  }
    -
    8923  for(size_t i = 0; i < count; ++i)
    -
    8924  {
    -
    8925  m_SB.Add(INDENT);
    -
    8926  }
    -
    8927  }
    -
    8928 }
    -
    8929 
    -
    8930 #endif // #if VMA_STATS_STRING_ENABLED
    -
    8931 
    -
    8933 
    -
    8934 void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData)
    -
    8935 {
    -
    8936  if(IsUserDataString())
    -
    8937  {
    -
    8938  VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData);
    -
    8939 
    -
    8940  FreeUserDataString(hAllocator);
    -
    8941 
    -
    8942  if(pUserData != VMA_NULL)
    -
    8943  {
    -
    8944  m_pUserData = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), (const char*)pUserData);
    -
    8945  }
    -
    8946  }
    -
    8947  else
    -
    8948  {
    -
    8949  m_pUserData = pUserData;
    -
    8950  }
    -
    8951 }
    -
    8952 
    -
    8953 void VmaAllocation_T::ChangeBlockAllocation(
    -
    8954  VmaAllocator hAllocator,
    -
    8955  VmaDeviceMemoryBlock* block,
    -
    8956  VkDeviceSize offset)
    -
    8957 {
    -
    8958  VMA_ASSERT(block != VMA_NULL);
    -
    8959  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    -
    8960 
    -
    8961  // Move mapping reference counter from old block to new block.
    -
    8962  if(block != m_BlockAllocation.m_Block)
    +
    8923  ++currItem.valueCount;
    +
    8924  }
    +
    8925 }
    +
    8926 
    +
    8927 void VmaJsonWriter::WriteIndent(bool oneLess)
    +
    8928 {
    +
    8929  if(!m_Stack.empty() && !m_Stack.back().singleLineMode)
    +
    8930  {
    +
    8931  m_SB.AddNewLine();
    +
    8932 
    +
    8933  size_t count = m_Stack.size();
    +
    8934  if(count > 0 && oneLess)
    +
    8935  {
    +
    8936  --count;
    +
    8937  }
    +
    8938  for(size_t i = 0; i < count; ++i)
    +
    8939  {
    +
    8940  m_SB.Add(INDENT);
    +
    8941  }
    +
    8942  }
    +
    8943 }
    +
    8944 
    +
    8945 #endif // #if VMA_STATS_STRING_ENABLED
    +
    8946 
    +
    8948 
    +
    8949 void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData)
    +
    8950 {
    +
    8951  if(IsUserDataString())
    +
    8952  {
    +
    8953  VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData);
    +
    8954 
    +
    8955  FreeUserDataString(hAllocator);
    +
    8956 
    +
    8957  if(pUserData != VMA_NULL)
    +
    8958  {
    +
    8959  m_pUserData = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), (const char*)pUserData);
    +
    8960  }
    +
    8961  }
    +
    8962  else
    8963  {
    -
    8964  uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP;
    -
    8965  if(IsPersistentMap())
    -
    8966  ++mapRefCount;
    -
    8967  m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount);
    -
    8968  block->Map(hAllocator, mapRefCount, VMA_NULL);
    -
    8969  }
    -
    8970 
    -
    8971  m_BlockAllocation.m_Block = block;
    -
    8972  m_BlockAllocation.m_Offset = offset;
    -
    8973 }
    -
    8974 
    -
    8975 void VmaAllocation_T::ChangeOffset(VkDeviceSize newOffset)
    -
    8976 {
    -
    8977  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    -
    8978  m_BlockAllocation.m_Offset = newOffset;
    -
    8979 }
    -
    8980 
    -
    8981 VkDeviceSize VmaAllocation_T::GetOffset() const
    -
    8982 {
    -
    8983  switch(m_Type)
    -
    8984  {
    -
    8985  case ALLOCATION_TYPE_BLOCK:
    -
    8986  return m_BlockAllocation.m_Offset;
    -
    8987  case ALLOCATION_TYPE_DEDICATED:
    -
    8988  return 0;
    -
    8989  default:
    -
    8990  VMA_ASSERT(0);
    -
    8991  return 0;
    -
    8992  }
    -
    8993 }
    -
    8994 
    -
    8995 VkDeviceMemory VmaAllocation_T::GetMemory() const
    -
    8996 {
    -
    8997  switch(m_Type)
    -
    8998  {
    -
    8999  case ALLOCATION_TYPE_BLOCK:
    -
    9000  return m_BlockAllocation.m_Block->GetDeviceMemory();
    -
    9001  case ALLOCATION_TYPE_DEDICATED:
    -
    9002  return m_DedicatedAllocation.m_hMemory;
    -
    9003  default:
    -
    9004  VMA_ASSERT(0);
    -
    9005  return VK_NULL_HANDLE;
    -
    9006  }
    -
    9007 }
    -
    9008 
    -
    9009 void* VmaAllocation_T::GetMappedData() const
    -
    9010 {
    -
    9011  switch(m_Type)
    -
    9012  {
    -
    9013  case ALLOCATION_TYPE_BLOCK:
    -
    9014  if(m_MapCount != 0)
    -
    9015  {
    -
    9016  void* pBlockData = m_BlockAllocation.m_Block->GetMappedData();
    -
    9017  VMA_ASSERT(pBlockData != VMA_NULL);
    -
    9018  return (char*)pBlockData + m_BlockAllocation.m_Offset;
    -
    9019  }
    -
    9020  else
    -
    9021  {
    -
    9022  return VMA_NULL;
    -
    9023  }
    -
    9024  break;
    -
    9025  case ALLOCATION_TYPE_DEDICATED:
    -
    9026  VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0));
    -
    9027  return m_DedicatedAllocation.m_pMappedData;
    -
    9028  default:
    -
    9029  VMA_ASSERT(0);
    -
    9030  return VMA_NULL;
    -
    9031  }
    -
    9032 }
    -
    9033 
    -
    9034 bool VmaAllocation_T::CanBecomeLost() const
    -
    9035 {
    -
    9036  switch(m_Type)
    -
    9037  {
    -
    9038  case ALLOCATION_TYPE_BLOCK:
    -
    9039  return m_BlockAllocation.m_CanBecomeLost;
    +
    8964  m_pUserData = pUserData;
    +
    8965  }
    +
    8966 }
    +
    8967 
    +
    8968 void VmaAllocation_T::ChangeBlockAllocation(
    +
    8969  VmaAllocator hAllocator,
    +
    8970  VmaDeviceMemoryBlock* block,
    +
    8971  VkDeviceSize offset)
    +
    8972 {
    +
    8973  VMA_ASSERT(block != VMA_NULL);
    +
    8974  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    +
    8975 
    +
    8976  // Move mapping reference counter from old block to new block.
    +
    8977  if(block != m_BlockAllocation.m_Block)
    +
    8978  {
    +
    8979  uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP;
    +
    8980  if(IsPersistentMap())
    +
    8981  ++mapRefCount;
    +
    8982  m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount);
    +
    8983  block->Map(hAllocator, mapRefCount, VMA_NULL);
    +
    8984  }
    +
    8985 
    +
    8986  m_BlockAllocation.m_Block = block;
    +
    8987  m_BlockAllocation.m_Offset = offset;
    +
    8988 }
    +
    8989 
    +
    8990 void VmaAllocation_T::ChangeOffset(VkDeviceSize newOffset)
    +
    8991 {
    +
    8992  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    +
    8993  m_BlockAllocation.m_Offset = newOffset;
    +
    8994 }
    +
    8995 
    +
    8996 VkDeviceSize VmaAllocation_T::GetOffset() const
    +
    8997 {
    +
    8998  switch(m_Type)
    +
    8999  {
    +
    9000  case ALLOCATION_TYPE_BLOCK:
    +
    9001  return m_BlockAllocation.m_Offset;
    +
    9002  case ALLOCATION_TYPE_DEDICATED:
    +
    9003  return 0;
    +
    9004  default:
    +
    9005  VMA_ASSERT(0);
    +
    9006  return 0;
    +
    9007  }
    +
    9008 }
    +
    9009 
    +
    9010 VkDeviceMemory VmaAllocation_T::GetMemory() const
    +
    9011 {
    +
    9012  switch(m_Type)
    +
    9013  {
    +
    9014  case ALLOCATION_TYPE_BLOCK:
    +
    9015  return m_BlockAllocation.m_Block->GetDeviceMemory();
    +
    9016  case ALLOCATION_TYPE_DEDICATED:
    +
    9017  return m_DedicatedAllocation.m_hMemory;
    +
    9018  default:
    +
    9019  VMA_ASSERT(0);
    +
    9020  return VK_NULL_HANDLE;
    +
    9021  }
    +
    9022 }
    +
    9023 
    +
    9024 void* VmaAllocation_T::GetMappedData() const
    +
    9025 {
    +
    9026  switch(m_Type)
    +
    9027  {
    +
    9028  case ALLOCATION_TYPE_BLOCK:
    +
    9029  if(m_MapCount != 0)
    +
    9030  {
    +
    9031  void* pBlockData = m_BlockAllocation.m_Block->GetMappedData();
    +
    9032  VMA_ASSERT(pBlockData != VMA_NULL);
    +
    9033  return (char*)pBlockData + m_BlockAllocation.m_Offset;
    +
    9034  }
    +
    9035  else
    +
    9036  {
    +
    9037  return VMA_NULL;
    +
    9038  }
    +
    9039  break;
    9040  case ALLOCATION_TYPE_DEDICATED:
    -
    9041  return false;
    -
    9042  default:
    -
    9043  VMA_ASSERT(0);
    -
    9044  return false;
    -
    9045  }
    -
    9046 }
    -
    9047 
    -
    9048 bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    -
    9049 {
    -
    9050  VMA_ASSERT(CanBecomeLost());
    -
    9051 
    -
    9052  /*
    -
    9053  Warning: This is a carefully designed algorithm.
    -
    9054  Do not modify unless you really know what you're doing :)
    -
    9055  */
    -
    9056  uint32_t localLastUseFrameIndex = GetLastUseFrameIndex();
    -
    9057  for(;;)
    -
    9058  {
    -
    9059  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
    -
    9060  {
    -
    9061  VMA_ASSERT(0);
    -
    9062  return false;
    -
    9063  }
    -
    9064  else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex)
    -
    9065  {
    -
    9066  return false;
    -
    9067  }
    -
    9068  else // Last use time earlier than current time.
    -
    9069  {
    -
    9070  if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST))
    -
    9071  {
    -
    9072  // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST.
    -
    9073  // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock.
    -
    9074  return true;
    -
    9075  }
    -
    9076  }
    -
    9077  }
    -
    9078 }
    -
    9079 
    -
    9080 #if VMA_STATS_STRING_ENABLED
    -
    9081 
    -
    9082 // Correspond to values of enum VmaSuballocationType.
    -
    9083 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
    -
    9084  "FREE",
    -
    9085  "UNKNOWN",
    -
    9086  "BUFFER",
    -
    9087  "IMAGE_UNKNOWN",
    -
    9088  "IMAGE_LINEAR",
    -
    9089  "IMAGE_OPTIMAL",
    -
    9090 };
    -
    9091 
    -
    9092 void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
    -
    9093 {
    -
    9094  json.WriteString("Type");
    -
    9095  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]);
    +
    9041  VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0));
    +
    9042  return m_DedicatedAllocation.m_pMappedData;
    +
    9043  default:
    +
    9044  VMA_ASSERT(0);
    +
    9045  return VMA_NULL;
    +
    9046  }
    +
    9047 }
    +
    9048 
    +
    9049 bool VmaAllocation_T::CanBecomeLost() const
    +
    9050 {
    +
    9051  switch(m_Type)
    +
    9052  {
    +
    9053  case ALLOCATION_TYPE_BLOCK:
    +
    9054  return m_BlockAllocation.m_CanBecomeLost;
    +
    9055  case ALLOCATION_TYPE_DEDICATED:
    +
    9056  return false;
    +
    9057  default:
    +
    9058  VMA_ASSERT(0);
    +
    9059  return false;
    +
    9060  }
    +
    9061 }
    +
    9062 
    +
    9063 bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    +
    9064 {
    +
    9065  VMA_ASSERT(CanBecomeLost());
    +
    9066 
    +
    9067  /*
    +
    9068  Warning: This is a carefully designed algorithm.
    +
    9069  Do not modify unless you really know what you're doing :)
    +
    9070  */
    +
    9071  uint32_t localLastUseFrameIndex = GetLastUseFrameIndex();
    +
    9072  for(;;)
    +
    9073  {
    +
    9074  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
    +
    9075  {
    +
    9076  VMA_ASSERT(0);
    +
    9077  return false;
    +
    9078  }
    +
    9079  else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex)
    +
    9080  {
    +
    9081  return false;
    +
    9082  }
    +
    9083  else // Last use time earlier than current time.
    +
    9084  {
    +
    9085  if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST))
    +
    9086  {
    +
    9087  // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST.
    +
    9088  // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock.
    +
    9089  return true;
    +
    9090  }
    +
    9091  }
    +
    9092  }
    +
    9093 }
    +
    9094 
    +
    9095 #if VMA_STATS_STRING_ENABLED
    9096 
    -
    9097  json.WriteString("Size");
    -
    9098  json.WriteNumber(m_Size);
    -
    9099 
    -
    9100  if(m_pUserData != VMA_NULL)
    -
    9101  {
    -
    9102  json.WriteString("UserData");
    -
    9103  if(IsUserDataString())
    -
    9104  {
    -
    9105  json.WriteString((const char*)m_pUserData);
    -
    9106  }
    -
    9107  else
    -
    9108  {
    -
    9109  json.BeginString();
    -
    9110  json.ContinueString_Pointer(m_pUserData);
    -
    9111  json.EndString();
    -
    9112  }
    -
    9113  }
    +
    9097 // Correspond to values of enum VmaSuballocationType.
    +
    9098 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
    +
    9099  "FREE",
    +
    9100  "UNKNOWN",
    +
    9101  "BUFFER",
    +
    9102  "IMAGE_UNKNOWN",
    +
    9103  "IMAGE_LINEAR",
    +
    9104  "IMAGE_OPTIMAL",
    +
    9105 };
    +
    9106 
    +
    9107 void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
    +
    9108 {
    +
    9109  json.WriteString("Type");
    +
    9110  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]);
    +
    9111 
    +
    9112  json.WriteString("Size");
    +
    9113  json.WriteNumber(m_Size);
    9114 
    -
    9115  json.WriteString("CreationFrameIndex");
    -
    9116  json.WriteNumber(m_CreationFrameIndex);
    -
    9117 
    -
    9118  json.WriteString("LastUseFrameIndex");
    -
    9119  json.WriteNumber(GetLastUseFrameIndex());
    -
    9120 
    -
    9121  if(m_BufferImageUsage != 0)
    -
    9122  {
    -
    9123  json.WriteString("Usage");
    -
    9124  json.WriteNumber(m_BufferImageUsage);
    -
    9125  }
    -
    9126 }
    -
    9127 
    -
    9128 #endif
    +
    9115  if(m_pUserData != VMA_NULL)
    +
    9116  {
    +
    9117  json.WriteString("UserData");
    +
    9118  if(IsUserDataString())
    +
    9119  {
    +
    9120  json.WriteString((const char*)m_pUserData);
    +
    9121  }
    +
    9122  else
    +
    9123  {
    +
    9124  json.BeginString();
    +
    9125  json.ContinueString_Pointer(m_pUserData);
    +
    9126  json.EndString();
    +
    9127  }
    +
    9128  }
    9129 
    -
    9130 void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator)
    -
    9131 {
    -
    9132  VMA_ASSERT(IsUserDataString());
    -
    9133  VmaFreeString(hAllocator->GetAllocationCallbacks(), (char*)m_pUserData);
    -
    9134  m_pUserData = VMA_NULL;
    -
    9135 }
    -
    9136 
    -
    9137 void VmaAllocation_T::BlockAllocMap()
    -
    9138 {
    -
    9139  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
    -
    9140 
    -
    9141  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
    -
    9142  {
    -
    9143  ++m_MapCount;
    -
    9144  }
    -
    9145  else
    -
    9146  {
    -
    9147  VMA_ASSERT(0 && "Allocation mapped too many times simultaneously.");
    -
    9148  }
    -
    9149 }
    -
    9150 
    -
    9151 void VmaAllocation_T::BlockAllocUnmap()
    -
    9152 {
    -
    9153  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
    -
    9154 
    -
    9155  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
    -
    9156  {
    -
    9157  --m_MapCount;
    -
    9158  }
    -
    9159  else
    -
    9160  {
    -
    9161  VMA_ASSERT(0 && "Unmapping allocation not previously mapped.");
    -
    9162  }
    -
    9163 }
    -
    9164 
    -
    9165 VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData)
    -
    9166 {
    -
    9167  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
    -
    9168 
    -
    9169  if(m_MapCount != 0)
    -
    9170  {
    -
    9171  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
    -
    9172  {
    -
    9173  VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL);
    -
    9174  *ppData = m_DedicatedAllocation.m_pMappedData;
    -
    9175  ++m_MapCount;
    -
    9176  return VK_SUCCESS;
    -
    9177  }
    -
    9178  else
    -
    9179  {
    -
    9180  VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously.");
    -
    9181  return VK_ERROR_MEMORY_MAP_FAILED;
    -
    9182  }
    -
    9183  }
    -
    9184  else
    +
    9130  json.WriteString("CreationFrameIndex");
    +
    9131  json.WriteNumber(m_CreationFrameIndex);
    +
    9132 
    +
    9133  json.WriteString("LastUseFrameIndex");
    +
    9134  json.WriteNumber(GetLastUseFrameIndex());
    +
    9135 
    +
    9136  if(m_BufferImageUsage != 0)
    +
    9137  {
    +
    9138  json.WriteString("Usage");
    +
    9139  json.WriteNumber(m_BufferImageUsage);
    +
    9140  }
    +
    9141 }
    +
    9142 
    +
    9143 #endif
    +
    9144 
    +
    9145 void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator)
    +
    9146 {
    +
    9147  VMA_ASSERT(IsUserDataString());
    +
    9148  VmaFreeString(hAllocator->GetAllocationCallbacks(), (char*)m_pUserData);
    +
    9149  m_pUserData = VMA_NULL;
    +
    9150 }
    +
    9151 
    +
    9152 void VmaAllocation_T::BlockAllocMap()
    +
    9153 {
    +
    9154  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
    +
    9155 
    +
    9156  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
    +
    9157  {
    +
    9158  ++m_MapCount;
    +
    9159  }
    +
    9160  else
    +
    9161  {
    +
    9162  VMA_ASSERT(0 && "Allocation mapped too many times simultaneously.");
    +
    9163  }
    +
    9164 }
    +
    9165 
    +
    9166 void VmaAllocation_T::BlockAllocUnmap()
    +
    9167 {
    +
    9168  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
    +
    9169 
    +
    9170  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
    +
    9171  {
    +
    9172  --m_MapCount;
    +
    9173  }
    +
    9174  else
    +
    9175  {
    +
    9176  VMA_ASSERT(0 && "Unmapping allocation not previously mapped.");
    +
    9177  }
    +
    9178 }
    +
    9179 
    +
    9180 VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData)
    +
    9181 {
    +
    9182  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
    +
    9183 
    +
    9184  if(m_MapCount != 0)
    9185  {
    -
    9186  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
    -
    9187  hAllocator->m_hDevice,
    -
    9188  m_DedicatedAllocation.m_hMemory,
    -
    9189  0, // offset
    -
    9190  VK_WHOLE_SIZE,
    -
    9191  0, // flags
    -
    9192  ppData);
    -
    9193  if(result == VK_SUCCESS)
    +
    9186  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
    +
    9187  {
    +
    9188  VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL);
    +
    9189  *ppData = m_DedicatedAllocation.m_pMappedData;
    +
    9190  ++m_MapCount;
    +
    9191  return VK_SUCCESS;
    +
    9192  }
    +
    9193  else
    9194  {
    -
    9195  m_DedicatedAllocation.m_pMappedData = *ppData;
    -
    9196  m_MapCount = 1;
    +
    9195  VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously.");
    +
    9196  return VK_ERROR_MEMORY_MAP_FAILED;
    9197  }
    -
    9198  return result;
    -
    9199  }
    -
    9200 }
    -
    9201 
    -
    9202 void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
    -
    9203 {
    -
    9204  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
    -
    9205 
    -
    9206  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
    -
    9207  {
    -
    9208  --m_MapCount;
    -
    9209  if(m_MapCount == 0)
    -
    9210  {
    -
    9211  m_DedicatedAllocation.m_pMappedData = VMA_NULL;
    -
    9212  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
    -
    9213  hAllocator->m_hDevice,
    -
    9214  m_DedicatedAllocation.m_hMemory);
    -
    9215  }
    -
    9216  }
    -
    9217  else
    -
    9218  {
    -
    9219  VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped.");
    -
    9220  }
    -
    9221 }
    -
    9222 
    -
    9223 #if VMA_STATS_STRING_ENABLED
    -
    9224 
    -
    9225 static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat)
    -
    9226 {
    -
    9227  json.BeginObject();
    -
    9228 
    -
    9229  json.WriteString("Blocks");
    -
    9230  json.WriteNumber(stat.blockCount);
    -
    9231 
    -
    9232  json.WriteString("Allocations");
    -
    9233  json.WriteNumber(stat.allocationCount);
    -
    9234 
    -
    9235  json.WriteString("UnusedRanges");
    -
    9236  json.WriteNumber(stat.unusedRangeCount);
    +
    9198  }
    +
    9199  else
    +
    9200  {
    +
    9201  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
    +
    9202  hAllocator->m_hDevice,
    +
    9203  m_DedicatedAllocation.m_hMemory,
    +
    9204  0, // offset
    +
    9205  VK_WHOLE_SIZE,
    +
    9206  0, // flags
    +
    9207  ppData);
    +
    9208  if(result == VK_SUCCESS)
    +
    9209  {
    +
    9210  m_DedicatedAllocation.m_pMappedData = *ppData;
    +
    9211  m_MapCount = 1;
    +
    9212  }
    +
    9213  return result;
    +
    9214  }
    +
    9215 }
    +
    9216 
    +
    9217 void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
    +
    9218 {
    +
    9219  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
    +
    9220 
    +
    9221  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
    +
    9222  {
    +
    9223  --m_MapCount;
    +
    9224  if(m_MapCount == 0)
    +
    9225  {
    +
    9226  m_DedicatedAllocation.m_pMappedData = VMA_NULL;
    +
    9227  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
    +
    9228  hAllocator->m_hDevice,
    +
    9229  m_DedicatedAllocation.m_hMemory);
    +
    9230  }
    +
    9231  }
    +
    9232  else
    +
    9233  {
    +
    9234  VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped.");
    +
    9235  }
    +
    9236 }
    9237 
    -
    9238  json.WriteString("UsedBytes");
    -
    9239  json.WriteNumber(stat.usedBytes);
    -
    9240 
    -
    9241  json.WriteString("UnusedBytes");
    -
    9242  json.WriteNumber(stat.unusedBytes);
    +
    9238 #if VMA_STATS_STRING_ENABLED
    +
    9239 
    +
    9240 static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat)
    +
    9241 {
    +
    9242  json.BeginObject();
    9243 
    -
    9244  if(stat.allocationCount > 1)
    -
    9245  {
    -
    9246  json.WriteString("AllocationSize");
    -
    9247  json.BeginObject(true);
    -
    9248  json.WriteString("Min");
    -
    9249  json.WriteNumber(stat.allocationSizeMin);
    -
    9250  json.WriteString("Avg");
    -
    9251  json.WriteNumber(stat.allocationSizeAvg);
    -
    9252  json.WriteString("Max");
    -
    9253  json.WriteNumber(stat.allocationSizeMax);
    -
    9254  json.EndObject();
    -
    9255  }
    -
    9256 
    -
    9257  if(stat.unusedRangeCount > 1)
    -
    9258  {
    -
    9259  json.WriteString("UnusedRangeSize");
    -
    9260  json.BeginObject(true);
    -
    9261  json.WriteString("Min");
    -
    9262  json.WriteNumber(stat.unusedRangeSizeMin);
    -
    9263  json.WriteString("Avg");
    -
    9264  json.WriteNumber(stat.unusedRangeSizeAvg);
    -
    9265  json.WriteString("Max");
    -
    9266  json.WriteNumber(stat.unusedRangeSizeMax);
    -
    9267  json.EndObject();
    -
    9268  }
    -
    9269 
    -
    9270  json.EndObject();
    -
    9271 }
    -
    9272 
    -
    9273 #endif // #if VMA_STATS_STRING_ENABLED
    -
    9274 
    -
    9275 struct VmaSuballocationItemSizeLess
    -
    9276 {
    -
    9277  bool operator()(
    -
    9278  const VmaSuballocationList::iterator lhs,
    -
    9279  const VmaSuballocationList::iterator rhs) const
    -
    9280  {
    -
    9281  return lhs->size < rhs->size;
    -
    9282  }
    -
    9283  bool operator()(
    -
    9284  const VmaSuballocationList::iterator lhs,
    -
    9285  VkDeviceSize rhsSize) const
    -
    9286  {
    -
    9287  return lhs->size < rhsSize;
    -
    9288  }
    -
    9289 };
    -
    9290 
    -
    9291 
    -
    9293 // class VmaBlockMetadata
    -
    9294 
    -
    9295 VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) :
    -
    9296  m_Size(0),
    -
    9297  m_pAllocationCallbacks(hAllocator->GetAllocationCallbacks())
    -
    9298 {
    -
    9299 }
    -
    9300 
    -
    9301 #if VMA_STATS_STRING_ENABLED
    -
    9302 
    -
    9303 void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
    -
    9304  VkDeviceSize unusedBytes,
    -
    9305  size_t allocationCount,
    -
    9306  size_t unusedRangeCount) const
    -
    9307 {
    -
    9308  json.BeginObject();
    +
    9244  json.WriteString("Blocks");
    +
    9245  json.WriteNumber(stat.blockCount);
    +
    9246 
    +
    9247  json.WriteString("Allocations");
    +
    9248  json.WriteNumber(stat.allocationCount);
    +
    9249 
    +
    9250  json.WriteString("UnusedRanges");
    +
    9251  json.WriteNumber(stat.unusedRangeCount);
    +
    9252 
    +
    9253  json.WriteString("UsedBytes");
    +
    9254  json.WriteNumber(stat.usedBytes);
    +
    9255 
    +
    9256  json.WriteString("UnusedBytes");
    +
    9257  json.WriteNumber(stat.unusedBytes);
    +
    9258 
    +
    9259  if(stat.allocationCount > 1)
    +
    9260  {
    +
    9261  json.WriteString("AllocationSize");
    +
    9262  json.BeginObject(true);
    +
    9263  json.WriteString("Min");
    +
    9264  json.WriteNumber(stat.allocationSizeMin);
    +
    9265  json.WriteString("Avg");
    +
    9266  json.WriteNumber(stat.allocationSizeAvg);
    +
    9267  json.WriteString("Max");
    +
    9268  json.WriteNumber(stat.allocationSizeMax);
    +
    9269  json.EndObject();
    +
    9270  }
    +
    9271 
    +
    9272  if(stat.unusedRangeCount > 1)
    +
    9273  {
    +
    9274  json.WriteString("UnusedRangeSize");
    +
    9275  json.BeginObject(true);
    +
    9276  json.WriteString("Min");
    +
    9277  json.WriteNumber(stat.unusedRangeSizeMin);
    +
    9278  json.WriteString("Avg");
    +
    9279  json.WriteNumber(stat.unusedRangeSizeAvg);
    +
    9280  json.WriteString("Max");
    +
    9281  json.WriteNumber(stat.unusedRangeSizeMax);
    +
    9282  json.EndObject();
    +
    9283  }
    +
    9284 
    +
    9285  json.EndObject();
    +
    9286 }
    +
    9287 
    +
    9288 #endif // #if VMA_STATS_STRING_ENABLED
    +
    9289 
    +
    9290 struct VmaSuballocationItemSizeLess
    +
    9291 {
    +
    9292  bool operator()(
    +
    9293  const VmaSuballocationList::iterator lhs,
    +
    9294  const VmaSuballocationList::iterator rhs) const
    +
    9295  {
    +
    9296  return lhs->size < rhs->size;
    +
    9297  }
    +
    9298  bool operator()(
    +
    9299  const VmaSuballocationList::iterator lhs,
    +
    9300  VkDeviceSize rhsSize) const
    +
    9301  {
    +
    9302  return lhs->size < rhsSize;
    +
    9303  }
    +
    9304 };
    +
    9305 
    +
    9306 
    +
    9308 // class VmaBlockMetadata
    9309 
    -
    9310  json.WriteString("TotalBytes");
    -
    9311  json.WriteNumber(GetSize());
    -
    9312 
    -
    9313  json.WriteString("UnusedBytes");
    -
    9314  json.WriteNumber(unusedBytes);
    +
    9310 VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) :
    +
    9311  m_Size(0),
    +
    9312  m_pAllocationCallbacks(hAllocator->GetAllocationCallbacks())
    +
    9313 {
    +
    9314 }
    9315 
    -
    9316  json.WriteString("Allocations");
    -
    9317  json.WriteNumber((uint64_t)allocationCount);
    -
    9318 
    -
    9319  json.WriteString("UnusedRanges");
    -
    9320  json.WriteNumber((uint64_t)unusedRangeCount);
    -
    9321 
    -
    9322  json.WriteString("Suballocations");
    -
    9323  json.BeginArray();
    -
    9324 }
    -
    9325 
    -
    9326 void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json,
    -
    9327  VkDeviceSize offset,
    -
    9328  VmaAllocation hAllocation) const
    -
    9329 {
    -
    9330  json.BeginObject(true);
    -
    9331 
    -
    9332  json.WriteString("Offset");
    -
    9333  json.WriteNumber(offset);
    -
    9334 
    -
    9335  hAllocation->PrintParameters(json);
    +
    9316 #if VMA_STATS_STRING_ENABLED
    +
    9317 
    +
    9318 void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
    +
    9319  VkDeviceSize unusedBytes,
    +
    9320  size_t allocationCount,
    +
    9321  size_t unusedRangeCount) const
    +
    9322 {
    +
    9323  json.BeginObject();
    +
    9324 
    +
    9325  json.WriteString("TotalBytes");
    +
    9326  json.WriteNumber(GetSize());
    +
    9327 
    +
    9328  json.WriteString("UnusedBytes");
    +
    9329  json.WriteNumber(unusedBytes);
    +
    9330 
    +
    9331  json.WriteString("Allocations");
    +
    9332  json.WriteNumber((uint64_t)allocationCount);
    +
    9333 
    +
    9334  json.WriteString("UnusedRanges");
    +
    9335  json.WriteNumber((uint64_t)unusedRangeCount);
    9336 
    -
    9337  json.EndObject();
    -
    9338 }
    -
    9339 
    -
    9340 void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
    -
    9341  VkDeviceSize offset,
    -
    9342  VkDeviceSize size) const
    -
    9343 {
    -
    9344  json.BeginObject(true);
    -
    9345 
    -
    9346  json.WriteString("Offset");
    -
    9347  json.WriteNumber(offset);
    -
    9348 
    -
    9349  json.WriteString("Type");
    -
    9350  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]);
    +
    9337  json.WriteString("Suballocations");
    +
    9338  json.BeginArray();
    +
    9339 }
    +
    9340 
    +
    9341 void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json,
    +
    9342  VkDeviceSize offset,
    +
    9343  VmaAllocation hAllocation) const
    +
    9344 {
    +
    9345  json.BeginObject(true);
    +
    9346 
    +
    9347  json.WriteString("Offset");
    +
    9348  json.WriteNumber(offset);
    +
    9349 
    +
    9350  hAllocation->PrintParameters(json);
    9351 
    -
    9352  json.WriteString("Size");
    -
    9353  json.WriteNumber(size);
    +
    9352  json.EndObject();
    +
    9353 }
    9354 
    -
    9355  json.EndObject();
    -
    9356 }
    -
    9357 
    -
    9358 void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const
    -
    9359 {
    -
    9360  json.EndArray();
    -
    9361  json.EndObject();
    -
    9362 }
    +
    9355 void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
    +
    9356  VkDeviceSize offset,
    +
    9357  VkDeviceSize size) const
    +
    9358 {
    +
    9359  json.BeginObject(true);
    +
    9360 
    +
    9361  json.WriteString("Offset");
    +
    9362  json.WriteNumber(offset);
    9363 
    -
    9364 #endif // #if VMA_STATS_STRING_ENABLED
    -
    9365 
    -
    9367 // class VmaBlockMetadata_Generic
    -
    9368 
    -
    9369 VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(VmaAllocator hAllocator) :
    -
    9370  VmaBlockMetadata(hAllocator),
    -
    9371  m_FreeCount(0),
    -
    9372  m_SumFreeSize(0),
    -
    9373  m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    -
    9374  m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
    -
    9375 {
    -
    9376 }
    -
    9377 
    -
    9378 VmaBlockMetadata_Generic::~VmaBlockMetadata_Generic()
    -
    9379 {
    -
    9380 }
    -
    9381 
    -
    9382 void VmaBlockMetadata_Generic::Init(VkDeviceSize size)
    -
    9383 {
    -
    9384  VmaBlockMetadata::Init(size);
    -
    9385 
    -
    9386  m_FreeCount = 1;
    -
    9387  m_SumFreeSize = size;
    -
    9388 
    -
    9389  VmaSuballocation suballoc = {};
    -
    9390  suballoc.offset = 0;
    -
    9391  suballoc.size = size;
    -
    9392  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    9393  suballoc.hAllocation = VK_NULL_HANDLE;
    -
    9394 
    -
    9395  VMA_ASSERT(size > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
    -
    9396  m_Suballocations.push_back(suballoc);
    -
    9397  VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
    -
    9398  --suballocItem;
    -
    9399  m_FreeSuballocationsBySize.push_back(suballocItem);
    -
    9400 }
    -
    9401 
    -
    9402 bool VmaBlockMetadata_Generic::Validate() const
    -
    9403 {
    -
    9404  VMA_VALIDATE(!m_Suballocations.empty());
    -
    9405 
    -
    9406  // Expected offset of new suballocation as calculated from previous ones.
    -
    9407  VkDeviceSize calculatedOffset = 0;
    -
    9408  // Expected number of free suballocations as calculated from traversing their list.
    -
    9409  uint32_t calculatedFreeCount = 0;
    -
    9410  // Expected sum size of free suballocations as calculated from traversing their list.
    -
    9411  VkDeviceSize calculatedSumFreeSize = 0;
    -
    9412  // Expected number of free suballocations that should be registered in
    -
    9413  // m_FreeSuballocationsBySize calculated from traversing their list.
    -
    9414  size_t freeSuballocationsToRegister = 0;
    -
    9415  // True if previous visited suballocation was free.
    -
    9416  bool prevFree = false;
    -
    9417 
    -
    9418  for(const auto& subAlloc : m_Suballocations)
    -
    9419  {
    -
    9420  // Actual offset of this suballocation doesn't match expected one.
    -
    9421  VMA_VALIDATE(subAlloc.offset == calculatedOffset);
    -
    9422 
    -
    9423  const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    9424  // Two adjacent free suballocations are invalid. They should be merged.
    -
    9425  VMA_VALIDATE(!prevFree || !currFree);
    -
    9426 
    -
    9427  VMA_VALIDATE(currFree == (subAlloc.hAllocation == VK_NULL_HANDLE));
    -
    9428 
    -
    9429  if(currFree)
    -
    9430  {
    -
    9431  calculatedSumFreeSize += subAlloc.size;
    -
    9432  ++calculatedFreeCount;
    -
    9433  if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    9434  {
    -
    9435  ++freeSuballocationsToRegister;
    -
    9436  }
    +
    9364  json.WriteString("Type");
    +
    9365  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]);
    +
    9366 
    +
    9367  json.WriteString("Size");
    +
    9368  json.WriteNumber(size);
    +
    9369 
    +
    9370  json.EndObject();
    +
    9371 }
    +
    9372 
    +
    9373 void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const
    +
    9374 {
    +
    9375  json.EndArray();
    +
    9376  json.EndObject();
    +
    9377 }
    +
    9378 
    +
    9379 #endif // #if VMA_STATS_STRING_ENABLED
    +
    9380 
    +
    9382 // class VmaBlockMetadata_Generic
    +
    9383 
    +
    9384 VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(VmaAllocator hAllocator) :
    +
    9385  VmaBlockMetadata(hAllocator),
    +
    9386  m_FreeCount(0),
    +
    9387  m_SumFreeSize(0),
    +
    9388  m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    +
    9389  m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
    +
    9390 {
    +
    9391 }
    +
    9392 
    +
    9393 VmaBlockMetadata_Generic::~VmaBlockMetadata_Generic()
    +
    9394 {
    +
    9395 }
    +
    9396 
    +
    9397 void VmaBlockMetadata_Generic::Init(VkDeviceSize size)
    +
    9398 {
    +
    9399  VmaBlockMetadata::Init(size);
    +
    9400 
    +
    9401  m_FreeCount = 1;
    +
    9402  m_SumFreeSize = size;
    +
    9403 
    +
    9404  VmaSuballocation suballoc = {};
    +
    9405  suballoc.offset = 0;
    +
    9406  suballoc.size = size;
    +
    9407  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    9408  suballoc.hAllocation = VK_NULL_HANDLE;
    +
    9409 
    +
    9410  VMA_ASSERT(size > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
    +
    9411  m_Suballocations.push_back(suballoc);
    +
    9412  VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
    +
    9413  --suballocItem;
    +
    9414  m_FreeSuballocationsBySize.push_back(suballocItem);
    +
    9415 }
    +
    9416 
    +
    9417 bool VmaBlockMetadata_Generic::Validate() const
    +
    9418 {
    +
    9419  VMA_VALIDATE(!m_Suballocations.empty());
    +
    9420 
    +
    9421  // Expected offset of new suballocation as calculated from previous ones.
    +
    9422  VkDeviceSize calculatedOffset = 0;
    +
    9423  // Expected number of free suballocations as calculated from traversing their list.
    +
    9424  uint32_t calculatedFreeCount = 0;
    +
    9425  // Expected sum size of free suballocations as calculated from traversing their list.
    +
    9426  VkDeviceSize calculatedSumFreeSize = 0;
    +
    9427  // Expected number of free suballocations that should be registered in
    +
    9428  // m_FreeSuballocationsBySize calculated from traversing their list.
    +
    9429  size_t freeSuballocationsToRegister = 0;
    +
    9430  // True if previous visited suballocation was free.
    +
    9431  bool prevFree = false;
    +
    9432 
    +
    9433  for(const auto& subAlloc : m_Suballocations)
    +
    9434  {
    +
    9435  // Actual offset of this suballocation doesn't match expected one.
    +
    9436  VMA_VALIDATE(subAlloc.offset == calculatedOffset);
    9437 
    -
    9438  // Margin required between allocations - every free space must be at least that large.
    -
    9439  VMA_VALIDATE(subAlloc.size >= VMA_DEBUG_MARGIN);
    -
    9440  }
    -
    9441  else
    -
    9442  {
    -
    9443  VMA_VALIDATE(subAlloc.hAllocation->GetOffset() == subAlloc.offset);
    -
    9444  VMA_VALIDATE(subAlloc.hAllocation->GetSize() == subAlloc.size);
    -
    9445 
    -
    9446  // Margin required between allocations - previous allocation must be free.
    -
    9447  VMA_VALIDATE(VMA_DEBUG_MARGIN == 0 || prevFree);
    -
    9448  }
    -
    9449 
    -
    9450  calculatedOffset += subAlloc.size;
    -
    9451  prevFree = currFree;
    -
    9452  }
    -
    9453 
    -
    9454  // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
    -
    9455  // match expected one.
    -
    9456  VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
    -
    9457 
    -
    9458  VkDeviceSize lastSize = 0;
    -
    9459  for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
    -
    9460  {
    -
    9461  VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
    -
    9462 
    -
    9463  // Only free suballocations can be registered in m_FreeSuballocationsBySize.
    -
    9464  VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    9465  // They must be sorted by size ascending.
    -
    9466  VMA_VALIDATE(suballocItem->size >= lastSize);
    -
    9467 
    -
    9468  lastSize = suballocItem->size;
    -
    9469  }
    -
    9470 
    -
    9471  // Check if totals match calculated values.
    -
    9472  VMA_VALIDATE(ValidateFreeSuballocationList());
    -
    9473  VMA_VALIDATE(calculatedOffset == GetSize());
    -
    9474  VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
    -
    9475  VMA_VALIDATE(calculatedFreeCount == m_FreeCount);
    -
    9476 
    -
    9477  return true;
    -
    9478 }
    -
    9479 
    -
    9480 VkDeviceSize VmaBlockMetadata_Generic::GetUnusedRangeSizeMax() const
    -
    9481 {
    -
    9482  if(!m_FreeSuballocationsBySize.empty())
    -
    9483  {
    -
    9484  return m_FreeSuballocationsBySize.back()->size;
    -
    9485  }
    -
    9486  else
    -
    9487  {
    -
    9488  return 0;
    -
    9489  }
    -
    9490 }
    +
    9438  const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    9439  // Two adjacent free suballocations are invalid. They should be merged.
    +
    9440  VMA_VALIDATE(!prevFree || !currFree);
    +
    9441 
    +
    9442  VMA_VALIDATE(currFree == (subAlloc.hAllocation == VK_NULL_HANDLE));
    +
    9443 
    +
    9444  if(currFree)
    +
    9445  {
    +
    9446  calculatedSumFreeSize += subAlloc.size;
    +
    9447  ++calculatedFreeCount;
    +
    9448  if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    9449  {
    +
    9450  ++freeSuballocationsToRegister;
    +
    9451  }
    +
    9452 
    +
    9453  // Margin required between allocations - every free space must be at least that large.
    +
    9454  VMA_VALIDATE(subAlloc.size >= VMA_DEBUG_MARGIN);
    +
    9455  }
    +
    9456  else
    +
    9457  {
    +
    9458  VMA_VALIDATE(subAlloc.hAllocation->GetOffset() == subAlloc.offset);
    +
    9459  VMA_VALIDATE(subAlloc.hAllocation->GetSize() == subAlloc.size);
    +
    9460 
    +
    9461  // Margin required between allocations - previous allocation must be free.
    +
    9462  VMA_VALIDATE(VMA_DEBUG_MARGIN == 0 || prevFree);
    +
    9463  }
    +
    9464 
    +
    9465  calculatedOffset += subAlloc.size;
    +
    9466  prevFree = currFree;
    +
    9467  }
    +
    9468 
    +
    9469  // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
    +
    9470  // match expected one.
    +
    9471  VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
    +
    9472 
    +
    9473  VkDeviceSize lastSize = 0;
    +
    9474  for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
    +
    9475  {
    +
    9476  VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
    +
    9477 
    +
    9478  // Only free suballocations can be registered in m_FreeSuballocationsBySize.
    +
    9479  VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    9480  // They must be sorted by size ascending.
    +
    9481  VMA_VALIDATE(suballocItem->size >= lastSize);
    +
    9482 
    +
    9483  lastSize = suballocItem->size;
    +
    9484  }
    +
    9485 
    +
    9486  // Check if totals match calculated values.
    +
    9487  VMA_VALIDATE(ValidateFreeSuballocationList());
    +
    9488  VMA_VALIDATE(calculatedOffset == GetSize());
    +
    9489  VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
    +
    9490  VMA_VALIDATE(calculatedFreeCount == m_FreeCount);
    9491 
    -
    9492 bool VmaBlockMetadata_Generic::IsEmpty() const
    -
    9493 {
    -
    9494  return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
    -
    9495 }
    -
    9496 
    -
    9497 void VmaBlockMetadata_Generic::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
    -
    9498 {
    -
    9499  outInfo.blockCount = 1;
    -
    9500 
    -
    9501  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
    -
    9502  outInfo.allocationCount = rangeCount - m_FreeCount;
    -
    9503  outInfo.unusedRangeCount = m_FreeCount;
    -
    9504 
    -
    9505  outInfo.unusedBytes = m_SumFreeSize;
    -
    9506  outInfo.usedBytes = GetSize() - outInfo.unusedBytes;
    -
    9507 
    -
    9508  outInfo.allocationSizeMin = UINT64_MAX;
    -
    9509  outInfo.allocationSizeMax = 0;
    -
    9510  outInfo.unusedRangeSizeMin = UINT64_MAX;
    -
    9511  outInfo.unusedRangeSizeMax = 0;
    -
    9512 
    -
    9513  for(const auto& suballoc : m_Suballocations)
    -
    9514  {
    -
    9515  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    -
    9516  {
    -
    9517  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    -
    9518  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);
    -
    9519  }
    -
    9520  else
    -
    9521  {
    -
    9522  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);
    -
    9523  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);
    -
    9524  }
    -
    9525  }
    -
    9526 }
    +
    9492  return true;
    +
    9493 }
    +
    9494 
    +
    9495 VkDeviceSize VmaBlockMetadata_Generic::GetUnusedRangeSizeMax() const
    +
    9496 {
    +
    9497  if(!m_FreeSuballocationsBySize.empty())
    +
    9498  {
    +
    9499  return m_FreeSuballocationsBySize.back()->size;
    +
    9500  }
    +
    9501  else
    +
    9502  {
    +
    9503  return 0;
    +
    9504  }
    +
    9505 }
    +
    9506 
    +
    9507 bool VmaBlockMetadata_Generic::IsEmpty() const
    +
    9508 {
    +
    9509  return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
    +
    9510 }
    +
    9511 
    +
    9512 void VmaBlockMetadata_Generic::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
    +
    9513 {
    +
    9514  outInfo.blockCount = 1;
    +
    9515 
    +
    9516  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
    +
    9517  outInfo.allocationCount = rangeCount - m_FreeCount;
    +
    9518  outInfo.unusedRangeCount = m_FreeCount;
    +
    9519 
    +
    9520  outInfo.unusedBytes = m_SumFreeSize;
    +
    9521  outInfo.usedBytes = GetSize() - outInfo.unusedBytes;
    +
    9522 
    +
    9523  outInfo.allocationSizeMin = UINT64_MAX;
    +
    9524  outInfo.allocationSizeMax = 0;
    +
    9525  outInfo.unusedRangeSizeMin = UINT64_MAX;
    +
    9526  outInfo.unusedRangeSizeMax = 0;
    9527 
    -
    9528 void VmaBlockMetadata_Generic::AddPoolStats(VmaPoolStats& inoutStats) const
    -
    9529 {
    -
    9530  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
    -
    9531 
    -
    9532  inoutStats.size += GetSize();
    -
    9533  inoutStats.unusedSize += m_SumFreeSize;
    -
    9534  inoutStats.allocationCount += rangeCount - m_FreeCount;
    -
    9535  inoutStats.unusedRangeCount += m_FreeCount;
    -
    9536  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
    -
    9537 }
    -
    9538 
    -
    9539 #if VMA_STATS_STRING_ENABLED
    -
    9540 
    -
    9541 void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json) const
    -
    9542 {
    -
    9543  PrintDetailedMap_Begin(json,
    -
    9544  m_SumFreeSize, // unusedBytes
    -
    9545  m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount
    -
    9546  m_FreeCount); // unusedRangeCount
    -
    9547 
    -
    9548  size_t i = 0;
    -
    9549  for(const auto& suballoc : m_Suballocations)
    -
    9550  {
    -
    9551  if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    9552  {
    -
    9553  PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size);
    -
    9554  }
    -
    9555  else
    -
    9556  {
    -
    9557  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    -
    9558  }
    -
    9559  }
    -
    9560 
    -
    9561  PrintDetailedMap_End(json);
    -
    9562 }
    -
    9563 
    -
    9564 #endif // #if VMA_STATS_STRING_ENABLED
    -
    9565 
    -
    9566 bool VmaBlockMetadata_Generic::CreateAllocationRequest(
    -
    9567  uint32_t currentFrameIndex,
    -
    9568  uint32_t frameInUseCount,
    -
    9569  VkDeviceSize bufferImageGranularity,
    -
    9570  VkDeviceSize allocSize,
    -
    9571  VkDeviceSize allocAlignment,
    -
    9572  bool upperAddress,
    -
    9573  VmaSuballocationType allocType,
    -
    9574  bool canMakeOtherLost,
    -
    9575  uint32_t strategy,
    -
    9576  VmaAllocationRequest* pAllocationRequest)
    -
    9577 {
    -
    9578  VMA_ASSERT(allocSize > 0);
    -
    9579  VMA_ASSERT(!upperAddress);
    -
    9580  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    -
    9581  VMA_ASSERT(pAllocationRequest != VMA_NULL);
    -
    9582  VMA_HEAVY_ASSERT(Validate());
    -
    9583 
    -
    9584  pAllocationRequest->type = VmaAllocationRequestType::Normal;
    -
    9585 
    -
    9586  // There is not enough total free space in this block to fullfill the request: Early return.
    -
    9587  if(canMakeOtherLost == false &&
    -
    9588  m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)
    -
    9589  {
    -
    9590  return false;
    -
    9591  }
    -
    9592 
    -
    9593  // New algorithm, efficiently searching freeSuballocationsBySize.
    -
    9594  const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
    -
    9595  if(freeSuballocCount > 0)
    -
    9596  {
    -
    9597  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)
    -
    9598  {
    -
    9599  // Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN.
    -
    9600  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    -
    9601  m_FreeSuballocationsBySize.data(),
    -
    9602  m_FreeSuballocationsBySize.data() + freeSuballocCount,
    -
    9603  allocSize + 2 * VMA_DEBUG_MARGIN,
    -
    9604  VmaSuballocationItemSizeLess());
    -
    9605  size_t index = it - m_FreeSuballocationsBySize.data();
    -
    9606  for(; index < freeSuballocCount; ++index)
    -
    9607  {
    -
    9608  if(CheckAllocation(
    -
    9609  currentFrameIndex,
    -
    9610  frameInUseCount,
    -
    9611  bufferImageGranularity,
    -
    9612  allocSize,
    -
    9613  allocAlignment,
    -
    9614  allocType,
    -
    9615  m_FreeSuballocationsBySize[index],
    -
    9616  false, // canMakeOtherLost
    -
    9617  &pAllocationRequest->offset,
    -
    9618  &pAllocationRequest->itemsToMakeLostCount,
    -
    9619  &pAllocationRequest->sumFreeSize,
    -
    9620  &pAllocationRequest->sumItemSize))
    -
    9621  {
    -
    9622  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
    -
    9623  return true;
    -
    9624  }
    -
    9625  }
    -
    9626  }
    -
    9627  else if(strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET)
    -
    9628  {
    -
    9629  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
    -
    9630  it != m_Suballocations.end();
    -
    9631  ++it)
    -
    9632  {
    -
    9633  if(it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation(
    -
    9634  currentFrameIndex,
    -
    9635  frameInUseCount,
    -
    9636  bufferImageGranularity,
    -
    9637  allocSize,
    -
    9638  allocAlignment,
    -
    9639  allocType,
    -
    9640  it,
    -
    9641  false, // canMakeOtherLost
    -
    9642  &pAllocationRequest->offset,
    -
    9643  &pAllocationRequest->itemsToMakeLostCount,
    -
    9644  &pAllocationRequest->sumFreeSize,
    -
    9645  &pAllocationRequest->sumItemSize))
    -
    9646  {
    -
    9647  pAllocationRequest->item = it;
    -
    9648  return true;
    -
    9649  }
    -
    9650  }
    -
    9651  }
    -
    9652  else // WORST_FIT, FIRST_FIT
    -
    9653  {
    -
    9654  // Search staring from biggest suballocations.
    -
    9655  for(size_t index = freeSuballocCount; index--; )
    -
    9656  {
    -
    9657  if(CheckAllocation(
    -
    9658  currentFrameIndex,
    -
    9659  frameInUseCount,
    -
    9660  bufferImageGranularity,
    -
    9661  allocSize,
    -
    9662  allocAlignment,
    -
    9663  allocType,
    -
    9664  m_FreeSuballocationsBySize[index],
    -
    9665  false, // canMakeOtherLost
    -
    9666  &pAllocationRequest->offset,
    -
    9667  &pAllocationRequest->itemsToMakeLostCount,
    -
    9668  &pAllocationRequest->sumFreeSize,
    -
    9669  &pAllocationRequest->sumItemSize))
    -
    9670  {
    -
    9671  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
    -
    9672  return true;
    -
    9673  }
    -
    9674  }
    -
    9675  }
    -
    9676  }
    -
    9677 
    -
    9678  if(canMakeOtherLost)
    -
    9679  {
    -
    9680  // Brute-force algorithm. TODO: Come up with something better.
    -
    9681 
    -
    9682  bool found = false;
    -
    9683  VmaAllocationRequest tmpAllocRequest = {};
    -
    9684  tmpAllocRequest.type = VmaAllocationRequestType::Normal;
    -
    9685  for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin();
    -
    9686  suballocIt != m_Suballocations.end();
    -
    9687  ++suballocIt)
    -
    9688  {
    -
    9689  if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE ||
    -
    9690  suballocIt->hAllocation->CanBecomeLost())
    -
    9691  {
    -
    9692  if(CheckAllocation(
    -
    9693  currentFrameIndex,
    -
    9694  frameInUseCount,
    -
    9695  bufferImageGranularity,
    -
    9696  allocSize,
    -
    9697  allocAlignment,
    -
    9698  allocType,
    -
    9699  suballocIt,
    -
    9700  canMakeOtherLost,
    -
    9701  &tmpAllocRequest.offset,
    -
    9702  &tmpAllocRequest.itemsToMakeLostCount,
    -
    9703  &tmpAllocRequest.sumFreeSize,
    -
    9704  &tmpAllocRequest.sumItemSize))
    -
    9705  {
    -
    9706  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)
    -
    9707  {
    -
    9708  *pAllocationRequest = tmpAllocRequest;
    -
    9709  pAllocationRequest->item = suballocIt;
    -
    9710  break;
    -
    9711  }
    -
    9712  if(!found || tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())
    -
    9713  {
    -
    9714  *pAllocationRequest = tmpAllocRequest;
    -
    9715  pAllocationRequest->item = suballocIt;
    -
    9716  found = true;
    -
    9717  }
    -
    9718  }
    -
    9719  }
    -
    9720  }
    -
    9721 
    -
    9722  return found;
    -
    9723  }
    -
    9724 
    -
    9725  return false;
    -
    9726 }
    -
    9727 
    -
    9728 bool VmaBlockMetadata_Generic::MakeRequestedAllocationsLost(
    -
    9729  uint32_t currentFrameIndex,
    -
    9730  uint32_t frameInUseCount,
    -
    9731  VmaAllocationRequest* pAllocationRequest)
    -
    9732 {
    -
    9733  VMA_ASSERT(pAllocationRequest && pAllocationRequest->type == VmaAllocationRequestType::Normal);
    -
    9734 
    -
    9735  while(pAllocationRequest->itemsToMakeLostCount > 0)
    -
    9736  {
    -
    9737  if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    9738  {
    -
    9739  ++pAllocationRequest->item;
    -
    9740  }
    -
    9741  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
    -
    9742  VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE);
    -
    9743  VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost());
    -
    9744  if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    -
    9745  {
    -
    9746  pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item);
    -
    9747  --pAllocationRequest->itemsToMakeLostCount;
    -
    9748  }
    -
    9749  else
    -
    9750  {
    -
    9751  return false;
    -
    9752  }
    -
    9753  }
    -
    9754 
    -
    9755  VMA_HEAVY_ASSERT(Validate());
    -
    9756  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
    -
    9757  VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    9758 
    -
    9759  return true;
    -
    9760 }
    -
    9761 
    -
    9762 uint32_t VmaBlockMetadata_Generic::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    -
    9763 {
    -
    9764  uint32_t lostAllocationCount = 0;
    -
    9765  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
    -
    9766  it != m_Suballocations.end();
    -
    9767  ++it)
    -
    9768  {
    -
    9769  if(it->type != VMA_SUBALLOCATION_TYPE_FREE &&
    -
    9770  it->hAllocation->CanBecomeLost() &&
    -
    9771  it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    -
    9772  {
    -
    9773  it = FreeSuballocation(it);
    -
    9774  ++lostAllocationCount;
    -
    9775  }
    -
    9776  }
    -
    9777  return lostAllocationCount;
    -
    9778 }
    -
    9779 
    -
    9780 VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData)
    -
    9781 {
    -
    9782  for(auto& suballoc : m_Suballocations)
    +
    9528  for(const auto& suballoc : m_Suballocations)
    +
    9529  {
    +
    9530  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    +
    9531  {
    +
    9532  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    +
    9533  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);
    +
    9534  }
    +
    9535  else
    +
    9536  {
    +
    9537  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);
    +
    9538  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);
    +
    9539  }
    +
    9540  }
    +
    9541 }
    +
    9542 
    +
    9543 void VmaBlockMetadata_Generic::AddPoolStats(VmaPoolStats& inoutStats) const
    +
    9544 {
    +
    9545  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
    +
    9546 
    +
    9547  inoutStats.size += GetSize();
    +
    9548  inoutStats.unusedSize += m_SumFreeSize;
    +
    9549  inoutStats.allocationCount += rangeCount - m_FreeCount;
    +
    9550  inoutStats.unusedRangeCount += m_FreeCount;
    +
    9551  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
    +
    9552 }
    +
    9553 
    +
    9554 #if VMA_STATS_STRING_ENABLED
    +
    9555 
    +
    9556 void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json) const
    +
    9557 {
    +
    9558  PrintDetailedMap_Begin(json,
    +
    9559  m_SumFreeSize, // unusedBytes
    +
    9560  m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount
    +
    9561  m_FreeCount); // unusedRangeCount
    +
    9562 
    +
    9563  size_t i = 0;
    +
    9564  for(const auto& suballoc : m_Suballocations)
    +
    9565  {
    +
    9566  if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    9567  {
    +
    9568  PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size);
    +
    9569  }
    +
    9570  else
    +
    9571  {
    +
    9572  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    +
    9573  }
    +
    9574  }
    +
    9575 
    +
    9576  PrintDetailedMap_End(json);
    +
    9577 }
    +
    9578 
    +
    9579 #endif // #if VMA_STATS_STRING_ENABLED
    +
    9580 
    +
    9581 bool VmaBlockMetadata_Generic::CreateAllocationRequest(
    +
    9582  uint32_t currentFrameIndex,
    +
    9583  uint32_t frameInUseCount,
    +
    9584  VkDeviceSize bufferImageGranularity,
    +
    9585  VkDeviceSize allocSize,
    +
    9586  VkDeviceSize allocAlignment,
    +
    9587  bool upperAddress,
    +
    9588  VmaSuballocationType allocType,
    +
    9589  bool canMakeOtherLost,
    +
    9590  uint32_t strategy,
    +
    9591  VmaAllocationRequest* pAllocationRequest)
    +
    9592 {
    +
    9593  VMA_ASSERT(allocSize > 0);
    +
    9594  VMA_ASSERT(!upperAddress);
    +
    9595  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    +
    9596  VMA_ASSERT(pAllocationRequest != VMA_NULL);
    +
    9597  VMA_HEAVY_ASSERT(Validate());
    +
    9598 
    +
    9599  pAllocationRequest->type = VmaAllocationRequestType::Normal;
    +
    9600 
    +
    9601  // There is not enough total free space in this block to fullfill the request: Early return.
    +
    9602  if(canMakeOtherLost == false &&
    +
    9603  m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)
    +
    9604  {
    +
    9605  return false;
    +
    9606  }
    +
    9607 
    +
    9608  // New algorithm, efficiently searching freeSuballocationsBySize.
    +
    9609  const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
    +
    9610  if(freeSuballocCount > 0)
    +
    9611  {
    +
    9612  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)
    +
    9613  {
    +
    9614  // Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN.
    +
    9615  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    +
    9616  m_FreeSuballocationsBySize.data(),
    +
    9617  m_FreeSuballocationsBySize.data() + freeSuballocCount,
    +
    9618  allocSize + 2 * VMA_DEBUG_MARGIN,
    +
    9619  VmaSuballocationItemSizeLess());
    +
    9620  size_t index = it - m_FreeSuballocationsBySize.data();
    +
    9621  for(; index < freeSuballocCount; ++index)
    +
    9622  {
    +
    9623  if(CheckAllocation(
    +
    9624  currentFrameIndex,
    +
    9625  frameInUseCount,
    +
    9626  bufferImageGranularity,
    +
    9627  allocSize,
    +
    9628  allocAlignment,
    +
    9629  allocType,
    +
    9630  m_FreeSuballocationsBySize[index],
    +
    9631  false, // canMakeOtherLost
    +
    9632  &pAllocationRequest->offset,
    +
    9633  &pAllocationRequest->itemsToMakeLostCount,
    +
    9634  &pAllocationRequest->sumFreeSize,
    +
    9635  &pAllocationRequest->sumItemSize))
    +
    9636  {
    +
    9637  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
    +
    9638  return true;
    +
    9639  }
    +
    9640  }
    +
    9641  }
    +
    9642  else if(strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET)
    +
    9643  {
    +
    9644  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
    +
    9645  it != m_Suballocations.end();
    +
    9646  ++it)
    +
    9647  {
    +
    9648  if(it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation(
    +
    9649  currentFrameIndex,
    +
    9650  frameInUseCount,
    +
    9651  bufferImageGranularity,
    +
    9652  allocSize,
    +
    9653  allocAlignment,
    +
    9654  allocType,
    +
    9655  it,
    +
    9656  false, // canMakeOtherLost
    +
    9657  &pAllocationRequest->offset,
    +
    9658  &pAllocationRequest->itemsToMakeLostCount,
    +
    9659  &pAllocationRequest->sumFreeSize,
    +
    9660  &pAllocationRequest->sumItemSize))
    +
    9661  {
    +
    9662  pAllocationRequest->item = it;
    +
    9663  return true;
    +
    9664  }
    +
    9665  }
    +
    9666  }
    +
    9667  else // WORST_FIT, FIRST_FIT
    +
    9668  {
    +
    9669  // Search staring from biggest suballocations.
    +
    9670  for(size_t index = freeSuballocCount; index--; )
    +
    9671  {
    +
    9672  if(CheckAllocation(
    +
    9673  currentFrameIndex,
    +
    9674  frameInUseCount,
    +
    9675  bufferImageGranularity,
    +
    9676  allocSize,
    +
    9677  allocAlignment,
    +
    9678  allocType,
    +
    9679  m_FreeSuballocationsBySize[index],
    +
    9680  false, // canMakeOtherLost
    +
    9681  &pAllocationRequest->offset,
    +
    9682  &pAllocationRequest->itemsToMakeLostCount,
    +
    9683  &pAllocationRequest->sumFreeSize,
    +
    9684  &pAllocationRequest->sumItemSize))
    +
    9685  {
    +
    9686  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
    +
    9687  return true;
    +
    9688  }
    +
    9689  }
    +
    9690  }
    +
    9691  }
    +
    9692 
    +
    9693  if(canMakeOtherLost)
    +
    9694  {
    +
    9695  // Brute-force algorithm. TODO: Come up with something better.
    +
    9696 
    +
    9697  bool found = false;
    +
    9698  VmaAllocationRequest tmpAllocRequest = {};
    +
    9699  tmpAllocRequest.type = VmaAllocationRequestType::Normal;
    +
    9700  for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin();
    +
    9701  suballocIt != m_Suballocations.end();
    +
    9702  ++suballocIt)
    +
    9703  {
    +
    9704  if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE ||
    +
    9705  suballocIt->hAllocation->CanBecomeLost())
    +
    9706  {
    +
    9707  if(CheckAllocation(
    +
    9708  currentFrameIndex,
    +
    9709  frameInUseCount,
    +
    9710  bufferImageGranularity,
    +
    9711  allocSize,
    +
    9712  allocAlignment,
    +
    9713  allocType,
    +
    9714  suballocIt,
    +
    9715  canMakeOtherLost,
    +
    9716  &tmpAllocRequest.offset,
    +
    9717  &tmpAllocRequest.itemsToMakeLostCount,
    +
    9718  &tmpAllocRequest.sumFreeSize,
    +
    9719  &tmpAllocRequest.sumItemSize))
    +
    9720  {
    +
    9721  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)
    +
    9722  {
    +
    9723  *pAllocationRequest = tmpAllocRequest;
    +
    9724  pAllocationRequest->item = suballocIt;
    +
    9725  break;
    +
    9726  }
    +
    9727  if(!found || tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())
    +
    9728  {
    +
    9729  *pAllocationRequest = tmpAllocRequest;
    +
    9730  pAllocationRequest->item = suballocIt;
    +
    9731  found = true;
    +
    9732  }
    +
    9733  }
    +
    9734  }
    +
    9735  }
    +
    9736 
    +
    9737  return found;
    +
    9738  }
    +
    9739 
    +
    9740  return false;
    +
    9741 }
    +
    9742 
    +
    9743 bool VmaBlockMetadata_Generic::MakeRequestedAllocationsLost(
    +
    9744  uint32_t currentFrameIndex,
    +
    9745  uint32_t frameInUseCount,
    +
    9746  VmaAllocationRequest* pAllocationRequest)
    +
    9747 {
    +
    9748  VMA_ASSERT(pAllocationRequest && pAllocationRequest->type == VmaAllocationRequestType::Normal);
    +
    9749 
    +
    9750  while(pAllocationRequest->itemsToMakeLostCount > 0)
    +
    9751  {
    +
    9752  if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    9753  {
    +
    9754  ++pAllocationRequest->item;
    +
    9755  }
    +
    9756  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
    +
    9757  VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE);
    +
    9758  VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost());
    +
    9759  if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    +
    9760  {
    +
    9761  pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item);
    +
    9762  --pAllocationRequest->itemsToMakeLostCount;
    +
    9763  }
    +
    9764  else
    +
    9765  {
    +
    9766  return false;
    +
    9767  }
    +
    9768  }
    +
    9769 
    +
    9770  VMA_HEAVY_ASSERT(Validate());
    +
    9771  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
    +
    9772  VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    9773 
    +
    9774  return true;
    +
    9775 }
    +
    9776 
    +
    9777 uint32_t VmaBlockMetadata_Generic::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    +
    9778 {
    +
    9779  uint32_t lostAllocationCount = 0;
    +
    9780  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
    +
    9781  it != m_Suballocations.end();
    +
    9782  ++it)
    9783  {
    -
    9784  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    -
    9785  {
    -
    9786  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
    -
    9787  {
    -
    9788  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
    -
    9789  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    9790  }
    -
    9791  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
    -
    9792  {
    -
    9793  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
    -
    9794  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    9795  }
    -
    9796  }
    -
    9797  }
    -
    9798 
    -
    9799  return VK_SUCCESS;
    -
    9800 }
    -
    9801 
    -
    9802 void VmaBlockMetadata_Generic::Alloc(
    -
    9803  const VmaAllocationRequest& request,
    -
    9804  VmaSuballocationType type,
    -
    9805  VkDeviceSize allocSize,
    -
    9806  VmaAllocation hAllocation)
    -
    9807 {
    -
    9808  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
    -
    9809  VMA_ASSERT(request.item != m_Suballocations.end());
    -
    9810  VmaSuballocation& suballoc = *request.item;
    -
    9811  // Given suballocation is a free block.
    -
    9812  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    9813  // Given offset is inside this suballocation.
    -
    9814  VMA_ASSERT(request.offset >= suballoc.offset);
    -
    9815  const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
    -
    9816  VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
    -
    9817  const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
    -
    9818 
    -
    9819  // Unregister this free suballocation from m_FreeSuballocationsBySize and update
    -
    9820  // it to become used.
    -
    9821  UnregisterFreeSuballocation(request.item);
    -
    9822 
    -
    9823  suballoc.offset = request.offset;
    -
    9824  suballoc.size = allocSize;
    -
    9825  suballoc.type = type;
    -
    9826  suballoc.hAllocation = hAllocation;
    -
    9827 
    -
    9828  // If there are any free bytes remaining at the end, insert new free suballocation after current one.
    -
    9829  if(paddingEnd)
    -
    9830  {
    -
    9831  VmaSuballocation paddingSuballoc = {};
    -
    9832  paddingSuballoc.offset = request.offset + allocSize;
    -
    9833  paddingSuballoc.size = paddingEnd;
    -
    9834  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    9835  VmaSuballocationList::iterator next = request.item;
    -
    9836  ++next;
    -
    9837  const VmaSuballocationList::iterator paddingEndItem =
    -
    9838  m_Suballocations.insert(next, paddingSuballoc);
    -
    9839  RegisterFreeSuballocation(paddingEndItem);
    -
    9840  }
    -
    9841 
    -
    9842  // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
    -
    9843  if(paddingBegin)
    -
    9844  {
    -
    9845  VmaSuballocation paddingSuballoc = {};
    -
    9846  paddingSuballoc.offset = request.offset - paddingBegin;
    -
    9847  paddingSuballoc.size = paddingBegin;
    -
    9848  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    9849  const VmaSuballocationList::iterator paddingBeginItem =
    -
    9850  m_Suballocations.insert(request.item, paddingSuballoc);
    -
    9851  RegisterFreeSuballocation(paddingBeginItem);
    -
    9852  }
    -
    9853 
    -
    9854  // Update totals.
    -
    9855  m_FreeCount = m_FreeCount - 1;
    -
    9856  if(paddingBegin > 0)
    -
    9857  {
    -
    9858  ++m_FreeCount;
    -
    9859  }
    -
    9860  if(paddingEnd > 0)
    -
    9861  {
    -
    9862  ++m_FreeCount;
    -
    9863  }
    -
    9864  m_SumFreeSize -= allocSize;
    -
    9865 }
    -
    9866 
    -
    9867 void VmaBlockMetadata_Generic::Free(const VmaAllocation allocation)
    -
    9868 {
    -
    9869  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
    -
    9870  suballocItem != m_Suballocations.end();
    -
    9871  ++suballocItem)
    +
    9784  if(it->type != VMA_SUBALLOCATION_TYPE_FREE &&
    +
    9785  it->hAllocation->CanBecomeLost() &&
    +
    9786  it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    +
    9787  {
    +
    9788  it = FreeSuballocation(it);
    +
    9789  ++lostAllocationCount;
    +
    9790  }
    +
    9791  }
    +
    9792  return lostAllocationCount;
    +
    9793 }
    +
    9794 
    +
    9795 VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData)
    +
    9796 {
    +
    9797  for(auto& suballoc : m_Suballocations)
    +
    9798  {
    +
    9799  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    +
    9800  {
    +
    9801  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
    +
    9802  {
    +
    9803  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
    +
    9804  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    9805  }
    +
    9806  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
    +
    9807  {
    +
    9808  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
    +
    9809  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    9810  }
    +
    9811  }
    +
    9812  }
    +
    9813 
    +
    9814  return VK_SUCCESS;
    +
    9815 }
    +
    9816 
    +
    9817 void VmaBlockMetadata_Generic::Alloc(
    +
    9818  const VmaAllocationRequest& request,
    +
    9819  VmaSuballocationType type,
    +
    9820  VkDeviceSize allocSize,
    +
    9821  VmaAllocation hAllocation)
    +
    9822 {
    +
    9823  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
    +
    9824  VMA_ASSERT(request.item != m_Suballocations.end());
    +
    9825  VmaSuballocation& suballoc = *request.item;
    +
    9826  // Given suballocation is a free block.
    +
    9827  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    9828  // Given offset is inside this suballocation.
    +
    9829  VMA_ASSERT(request.offset >= suballoc.offset);
    +
    9830  const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
    +
    9831  VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
    +
    9832  const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
    +
    9833 
    +
    9834  // Unregister this free suballocation from m_FreeSuballocationsBySize and update
    +
    9835  // it to become used.
    +
    9836  UnregisterFreeSuballocation(request.item);
    +
    9837 
    +
    9838  suballoc.offset = request.offset;
    +
    9839  suballoc.size = allocSize;
    +
    9840  suballoc.type = type;
    +
    9841  suballoc.hAllocation = hAllocation;
    +
    9842 
    +
    9843  // If there are any free bytes remaining at the end, insert new free suballocation after current one.
    +
    9844  if(paddingEnd)
    +
    9845  {
    +
    9846  VmaSuballocation paddingSuballoc = {};
    +
    9847  paddingSuballoc.offset = request.offset + allocSize;
    +
    9848  paddingSuballoc.size = paddingEnd;
    +
    9849  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    9850  VmaSuballocationList::iterator next = request.item;
    +
    9851  ++next;
    +
    9852  const VmaSuballocationList::iterator paddingEndItem =
    +
    9853  m_Suballocations.insert(next, paddingSuballoc);
    +
    9854  RegisterFreeSuballocation(paddingEndItem);
    +
    9855  }
    +
    9856 
    +
    9857  // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
    +
    9858  if(paddingBegin)
    +
    9859  {
    +
    9860  VmaSuballocation paddingSuballoc = {};
    +
    9861  paddingSuballoc.offset = request.offset - paddingBegin;
    +
    9862  paddingSuballoc.size = paddingBegin;
    +
    9863  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    9864  const VmaSuballocationList::iterator paddingBeginItem =
    +
    9865  m_Suballocations.insert(request.item, paddingSuballoc);
    +
    9866  RegisterFreeSuballocation(paddingBeginItem);
    +
    9867  }
    +
    9868 
    +
    9869  // Update totals.
    +
    9870  m_FreeCount = m_FreeCount - 1;
    +
    9871  if(paddingBegin > 0)
    9872  {
    -
    9873  VmaSuballocation& suballoc = *suballocItem;
    -
    9874  if(suballoc.hAllocation == allocation)
    -
    9875  {
    -
    9876  FreeSuballocation(suballocItem);
    -
    9877  VMA_HEAVY_ASSERT(Validate());
    -
    9878  return;
    -
    9879  }
    -
    9880  }
    -
    9881  VMA_ASSERT(0 && "Not found!");
    -
    9882 }
    -
    9883 
    -
    9884 void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
    -
    9885 {
    -
    9886  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
    -
    9887  suballocItem != m_Suballocations.end();
    -
    9888  ++suballocItem)
    -
    9889  {
    -
    9890  VmaSuballocation& suballoc = *suballocItem;
    -
    9891  if(suballoc.offset == offset)
    -
    9892  {
    -
    9893  FreeSuballocation(suballocItem);
    -
    9894  return;
    -
    9895  }
    -
    9896  }
    -
    9897  VMA_ASSERT(0 && "Not found!");
    -
    9898 }
    -
    9899 
    -
    9900 bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
    -
    9901 {
    -
    9902  VkDeviceSize lastSize = 0;
    -
    9903  for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
    +
    9873  ++m_FreeCount;
    +
    9874  }
    +
    9875  if(paddingEnd > 0)
    +
    9876  {
    +
    9877  ++m_FreeCount;
    +
    9878  }
    +
    9879  m_SumFreeSize -= allocSize;
    +
    9880 }
    +
    9881 
    +
    9882 void VmaBlockMetadata_Generic::Free(const VmaAllocation allocation)
    +
    9883 {
    +
    9884  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
    +
    9885  suballocItem != m_Suballocations.end();
    +
    9886  ++suballocItem)
    +
    9887  {
    +
    9888  VmaSuballocation& suballoc = *suballocItem;
    +
    9889  if(suballoc.hAllocation == allocation)
    +
    9890  {
    +
    9891  FreeSuballocation(suballocItem);
    +
    9892  VMA_HEAVY_ASSERT(Validate());
    +
    9893  return;
    +
    9894  }
    +
    9895  }
    +
    9896  VMA_ASSERT(0 && "Not found!");
    +
    9897 }
    +
    9898 
    +
    9899 void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
    +
    9900 {
    +
    9901  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
    +
    9902  suballocItem != m_Suballocations.end();
    +
    9903  ++suballocItem)
    9904  {
    -
    9905  const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
    -
    9906 
    -
    9907  VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    9908  VMA_VALIDATE(it->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
    -
    9909  VMA_VALIDATE(it->size >= lastSize);
    -
    9910  lastSize = it->size;
    +
    9905  VmaSuballocation& suballoc = *suballocItem;
    +
    9906  if(suballoc.offset == offset)
    +
    9907  {
    +
    9908  FreeSuballocation(suballocItem);
    +
    9909  return;
    +
    9910  }
    9911  }
    -
    9912  return true;
    +
    9912  VMA_ASSERT(0 && "Not found!");
    9913 }
    9914 
    -
    9915 bool VmaBlockMetadata_Generic::CheckAllocation(
    -
    9916  uint32_t currentFrameIndex,
    -
    9917  uint32_t frameInUseCount,
    -
    9918  VkDeviceSize bufferImageGranularity,
    -
    9919  VkDeviceSize allocSize,
    -
    9920  VkDeviceSize allocAlignment,
    -
    9921  VmaSuballocationType allocType,
    -
    9922  VmaSuballocationList::const_iterator suballocItem,
    -
    9923  bool canMakeOtherLost,
    -
    9924  VkDeviceSize* pOffset,
    -
    9925  size_t* itemsToMakeLostCount,
    -
    9926  VkDeviceSize* pSumFreeSize,
    -
    9927  VkDeviceSize* pSumItemSize) const
    -
    9928 {
    -
    9929  VMA_ASSERT(allocSize > 0);
    -
    9930  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    -
    9931  VMA_ASSERT(suballocItem != m_Suballocations.cend());
    -
    9932  VMA_ASSERT(pOffset != VMA_NULL);
    -
    9933 
    -
    9934  *itemsToMakeLostCount = 0;
    -
    9935  *pSumFreeSize = 0;
    -
    9936  *pSumItemSize = 0;
    -
    9937 
    -
    9938  if(canMakeOtherLost)
    -
    9939  {
    -
    9940  if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    9941  {
    -
    9942  *pSumFreeSize = suballocItem->size;
    -
    9943  }
    -
    9944  else
    -
    9945  {
    -
    9946  if(suballocItem->hAllocation->CanBecomeLost() &&
    -
    9947  suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    -
    9948  {
    -
    9949  ++*itemsToMakeLostCount;
    -
    9950  *pSumItemSize = suballocItem->size;
    -
    9951  }
    -
    9952  else
    -
    9953  {
    -
    9954  return false;
    -
    9955  }
    -
    9956  }
    -
    9957 
    -
    9958  // Remaining size is too small for this request: Early return.
    -
    9959  if(GetSize() - suballocItem->offset < allocSize)
    +
    9915 bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
    +
    9916 {
    +
    9917  VkDeviceSize lastSize = 0;
    +
    9918  for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
    +
    9919  {
    +
    9920  const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
    +
    9921 
    +
    9922  VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    9923  VMA_VALIDATE(it->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
    +
    9924  VMA_VALIDATE(it->size >= lastSize);
    +
    9925  lastSize = it->size;
    +
    9926  }
    +
    9927  return true;
    +
    9928 }
    +
    9929 
    +
    9930 bool VmaBlockMetadata_Generic::CheckAllocation(
    +
    9931  uint32_t currentFrameIndex,
    +
    9932  uint32_t frameInUseCount,
    +
    9933  VkDeviceSize bufferImageGranularity,
    +
    9934  VkDeviceSize allocSize,
    +
    9935  VkDeviceSize allocAlignment,
    +
    9936  VmaSuballocationType allocType,
    +
    9937  VmaSuballocationList::const_iterator suballocItem,
    +
    9938  bool canMakeOtherLost,
    +
    9939  VkDeviceSize* pOffset,
    +
    9940  size_t* itemsToMakeLostCount,
    +
    9941  VkDeviceSize* pSumFreeSize,
    +
    9942  VkDeviceSize* pSumItemSize) const
    +
    9943 {
    +
    9944  VMA_ASSERT(allocSize > 0);
    +
    9945  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    +
    9946  VMA_ASSERT(suballocItem != m_Suballocations.cend());
    +
    9947  VMA_ASSERT(pOffset != VMA_NULL);
    +
    9948 
    +
    9949  *itemsToMakeLostCount = 0;
    +
    9950  *pSumFreeSize = 0;
    +
    9951  *pSumItemSize = 0;
    +
    9952 
    +
    9953  if(canMakeOtherLost)
    +
    9954  {
    +
    9955  if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    9956  {
    +
    9957  *pSumFreeSize = suballocItem->size;
    +
    9958  }
    +
    9959  else
    9960  {
    -
    9961  return false;
    -
    9962  }
    -
    9963 
    -
    9964  // Start from offset equal to beginning of this suballocation.
    -
    9965  *pOffset = suballocItem->offset;
    -
    9966 
    -
    9967  // Apply VMA_DEBUG_MARGIN at the beginning.
    -
    9968  if(VMA_DEBUG_MARGIN > 0)
    -
    9969  {
    -
    9970  *pOffset += VMA_DEBUG_MARGIN;
    +
    9961  if(suballocItem->hAllocation->CanBecomeLost() &&
    +
    9962  suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    +
    9963  {
    +
    9964  ++*itemsToMakeLostCount;
    +
    9965  *pSumItemSize = suballocItem->size;
    +
    9966  }
    +
    9967  else
    +
    9968  {
    +
    9969  return false;
    +
    9970  }
    9971  }
    9972 
    -
    9973  // Apply alignment.
    -
    9974  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
    -
    9975 
    -
    9976  // Check previous suballocations for BufferImageGranularity conflicts.
    -
    9977  // Make bigger alignment if necessary.
    -
    9978  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
    -
    9979  {
    -
    9980  bool bufferImageGranularityConflict = false;
    -
    9981  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
    -
    9982  while(prevSuballocItem != m_Suballocations.cbegin())
    -
    9983  {
    -
    9984  --prevSuballocItem;
    -
    9985  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
    -
    9986  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
    -
    9987  {
    -
    9988  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    -
    9989  {
    -
    9990  bufferImageGranularityConflict = true;
    -
    9991  break;
    -
    9992  }
    -
    9993  }
    -
    9994  else
    -
    9995  // Already on previous page.
    -
    9996  break;
    -
    9997  }
    -
    9998  if(bufferImageGranularityConflict)
    -
    9999  {
    -
    10000  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
    -
    10001  }
    -
    10002  }
    -
    10003 
    -
    10004  // Now that we have final *pOffset, check if we are past suballocItem.
    -
    10005  // If yes, return false - this function should be called for another suballocItem as starting point.
    -
    10006  if(*pOffset >= suballocItem->offset + suballocItem->size)
    -
    10007  {
    -
    10008  return false;
    -
    10009  }
    -
    10010 
    -
    10011  // Calculate padding at the beginning based on current offset.
    -
    10012  const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
    -
    10013 
    -
    10014  // Calculate required margin at the end.
    -
    10015  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
    -
    10016 
    -
    10017  const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
    -
    10018  // Another early return check.
    -
    10019  if(suballocItem->offset + totalSize > GetSize())
    -
    10020  {
    -
    10021  return false;
    -
    10022  }
    -
    10023 
    -
    10024  // Advance lastSuballocItem until desired size is reached.
    -
    10025  // Update itemsToMakeLostCount.
    -
    10026  VmaSuballocationList::const_iterator lastSuballocItem = suballocItem;
    -
    10027  if(totalSize > suballocItem->size)
    -
    10028  {
    -
    10029  VkDeviceSize remainingSize = totalSize - suballocItem->size;
    -
    10030  while(remainingSize > 0)
    -
    10031  {
    -
    10032  ++lastSuballocItem;
    -
    10033  if(lastSuballocItem == m_Suballocations.cend())
    -
    10034  {
    -
    10035  return false;
    -
    10036  }
    -
    10037  if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    10038  {
    -
    10039  *pSumFreeSize += lastSuballocItem->size;
    -
    10040  }
    -
    10041  else
    -
    10042  {
    -
    10043  VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE);
    -
    10044  if(lastSuballocItem->hAllocation->CanBecomeLost() &&
    -
    10045  lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    -
    10046  {
    -
    10047  ++*itemsToMakeLostCount;
    -
    10048  *pSumItemSize += lastSuballocItem->size;
    -
    10049  }
    -
    10050  else
    -
    10051  {
    -
    10052  return false;
    -
    10053  }
    -
    10054  }
    -
    10055  remainingSize = (lastSuballocItem->size < remainingSize) ?
    -
    10056  remainingSize - lastSuballocItem->size : 0;
    -
    10057  }
    -
    10058  }
    -
    10059 
    -
    10060  // Check next suballocations for BufferImageGranularity conflicts.
    -
    10061  // If conflict exists, we must mark more allocations lost or fail.
    -
    10062  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
    -
    10063  {
    -
    10064  VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
    -
    10065  ++nextSuballocItem;
    -
    10066  while(nextSuballocItem != m_Suballocations.cend())
    -
    10067  {
    -
    10068  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
    -
    10069  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    -
    10070  {
    -
    10071  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    -
    10072  {
    -
    10073  VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE);
    -
    10074  if(nextSuballoc.hAllocation->CanBecomeLost() &&
    -
    10075  nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    -
    10076  {
    -
    10077  ++*itemsToMakeLostCount;
    -
    10078  }
    -
    10079  else
    -
    10080  {
    -
    10081  return false;
    -
    10082  }
    -
    10083  }
    -
    10084  }
    -
    10085  else
    -
    10086  {
    -
    10087  // Already on next page.
    -
    10088  break;
    -
    10089  }
    -
    10090  ++nextSuballocItem;
    -
    10091  }
    -
    10092  }
    -
    10093  }
    -
    10094  else
    -
    10095  {
    -
    10096  const VmaSuballocation& suballoc = *suballocItem;
    -
    10097  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10098 
    -
    10099  *pSumFreeSize = suballoc.size;
    -
    10100 
    -
    10101  // Size of this suballocation is too small for this request: Early return.
    -
    10102  if(suballoc.size < allocSize)
    -
    10103  {
    -
    10104  return false;
    -
    10105  }
    -
    10106 
    -
    10107  // Start from offset equal to beginning of this suballocation.
    -
    10108  *pOffset = suballoc.offset;
    -
    10109 
    -
    10110  // Apply VMA_DEBUG_MARGIN at the beginning.
    -
    10111  if(VMA_DEBUG_MARGIN > 0)
    -
    10112  {
    -
    10113  *pOffset += VMA_DEBUG_MARGIN;
    -
    10114  }
    +
    9973  // Remaining size is too small for this request: Early return.
    +
    9974  if(GetSize() - suballocItem->offset < allocSize)
    +
    9975  {
    +
    9976  return false;
    +
    9977  }
    +
    9978 
    +
    9979  // Start from offset equal to beginning of this suballocation.
    +
    9980  *pOffset = suballocItem->offset;
    +
    9981 
    +
    9982  // Apply VMA_DEBUG_MARGIN at the beginning.
    +
    9983  if(VMA_DEBUG_MARGIN > 0)
    +
    9984  {
    +
    9985  *pOffset += VMA_DEBUG_MARGIN;
    +
    9986  }
    +
    9987 
    +
    9988  // Apply alignment.
    +
    9989  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
    +
    9990 
    +
    9991  // Check previous suballocations for BufferImageGranularity conflicts.
    +
    9992  // Make bigger alignment if necessary.
    +
    9993  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
    +
    9994  {
    +
    9995  bool bufferImageGranularityConflict = false;
    +
    9996  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
    +
    9997  while(prevSuballocItem != m_Suballocations.cbegin())
    +
    9998  {
    +
    9999  --prevSuballocItem;
    +
    10000  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
    +
    10001  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
    +
    10002  {
    +
    10003  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    +
    10004  {
    +
    10005  bufferImageGranularityConflict = true;
    +
    10006  break;
    +
    10007  }
    +
    10008  }
    +
    10009  else
    +
    10010  // Already on previous page.
    +
    10011  break;
    +
    10012  }
    +
    10013  if(bufferImageGranularityConflict)
    +
    10014  {
    +
    10015  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
    +
    10016  }
    +
    10017  }
    +
    10018 
    +
    10019  // Now that we have final *pOffset, check if we are past suballocItem.
    +
    10020  // If yes, return false - this function should be called for another suballocItem as starting point.
    +
    10021  if(*pOffset >= suballocItem->offset + suballocItem->size)
    +
    10022  {
    +
    10023  return false;
    +
    10024  }
    +
    10025 
    +
    10026  // Calculate padding at the beginning based on current offset.
    +
    10027  const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
    +
    10028 
    +
    10029  // Calculate required margin at the end.
    +
    10030  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
    +
    10031 
    +
    10032  const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
    +
    10033  // Another early return check.
    +
    10034  if(suballocItem->offset + totalSize > GetSize())
    +
    10035  {
    +
    10036  return false;
    +
    10037  }
    +
    10038 
    +
    10039  // Advance lastSuballocItem until desired size is reached.
    +
    10040  // Update itemsToMakeLostCount.
    +
    10041  VmaSuballocationList::const_iterator lastSuballocItem = suballocItem;
    +
    10042  if(totalSize > suballocItem->size)
    +
    10043  {
    +
    10044  VkDeviceSize remainingSize = totalSize - suballocItem->size;
    +
    10045  while(remainingSize > 0)
    +
    10046  {
    +
    10047  ++lastSuballocItem;
    +
    10048  if(lastSuballocItem == m_Suballocations.cend())
    +
    10049  {
    +
    10050  return false;
    +
    10051  }
    +
    10052  if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    10053  {
    +
    10054  *pSumFreeSize += lastSuballocItem->size;
    +
    10055  }
    +
    10056  else
    +
    10057  {
    +
    10058  VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE);
    +
    10059  if(lastSuballocItem->hAllocation->CanBecomeLost() &&
    +
    10060  lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    +
    10061  {
    +
    10062  ++*itemsToMakeLostCount;
    +
    10063  *pSumItemSize += lastSuballocItem->size;
    +
    10064  }
    +
    10065  else
    +
    10066  {
    +
    10067  return false;
    +
    10068  }
    +
    10069  }
    +
    10070  remainingSize = (lastSuballocItem->size < remainingSize) ?
    +
    10071  remainingSize - lastSuballocItem->size : 0;
    +
    10072  }
    +
    10073  }
    +
    10074 
    +
    10075  // Check next suballocations for BufferImageGranularity conflicts.
    +
    10076  // If conflict exists, we must mark more allocations lost or fail.
    +
    10077  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
    +
    10078  {
    +
    10079  VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
    +
    10080  ++nextSuballocItem;
    +
    10081  while(nextSuballocItem != m_Suballocations.cend())
    +
    10082  {
    +
    10083  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
    +
    10084  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    +
    10085  {
    +
    10086  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    +
    10087  {
    +
    10088  VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE);
    +
    10089  if(nextSuballoc.hAllocation->CanBecomeLost() &&
    +
    10090  nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    +
    10091  {
    +
    10092  ++*itemsToMakeLostCount;
    +
    10093  }
    +
    10094  else
    +
    10095  {
    +
    10096  return false;
    +
    10097  }
    +
    10098  }
    +
    10099  }
    +
    10100  else
    +
    10101  {
    +
    10102  // Already on next page.
    +
    10103  break;
    +
    10104  }
    +
    10105  ++nextSuballocItem;
    +
    10106  }
    +
    10107  }
    +
    10108  }
    +
    10109  else
    +
    10110  {
    +
    10111  const VmaSuballocation& suballoc = *suballocItem;
    +
    10112  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10113 
    +
    10114  *pSumFreeSize = suballoc.size;
    10115 
    -
    10116  // Apply alignment.
    -
    10117  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
    -
    10118 
    -
    10119  // Check previous suballocations for BufferImageGranularity conflicts.
    -
    10120  // Make bigger alignment if necessary.
    -
    10121  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
    -
    10122  {
    -
    10123  bool bufferImageGranularityConflict = false;
    -
    10124  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
    -
    10125  while(prevSuballocItem != m_Suballocations.cbegin())
    -
    10126  {
    -
    10127  --prevSuballocItem;
    -
    10128  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
    -
    10129  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
    -
    10130  {
    -
    10131  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    -
    10132  {
    -
    10133  bufferImageGranularityConflict = true;
    -
    10134  break;
    -
    10135  }
    -
    10136  }
    -
    10137  else
    -
    10138  // Already on previous page.
    -
    10139  break;
    -
    10140  }
    -
    10141  if(bufferImageGranularityConflict)
    -
    10142  {
    -
    10143  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
    -
    10144  }
    -
    10145  }
    -
    10146 
    -
    10147  // Calculate padding at the beginning based on current offset.
    -
    10148  const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
    -
    10149 
    -
    10150  // Calculate required margin at the end.
    -
    10151  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
    -
    10152 
    -
    10153  // Fail if requested size plus margin before and after is bigger than size of this suballocation.
    -
    10154  if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
    -
    10155  {
    -
    10156  return false;
    -
    10157  }
    -
    10158 
    -
    10159  // Check next suballocations for BufferImageGranularity conflicts.
    -
    10160  // If conflict exists, allocation cannot be made here.
    -
    10161  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
    -
    10162  {
    -
    10163  VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
    -
    10164  ++nextSuballocItem;
    -
    10165  while(nextSuballocItem != m_Suballocations.cend())
    -
    10166  {
    -
    10167  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
    -
    10168  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    -
    10169  {
    -
    10170  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    -
    10171  {
    -
    10172  return false;
    -
    10173  }
    -
    10174  }
    -
    10175  else
    -
    10176  {
    -
    10177  // Already on next page.
    -
    10178  break;
    -
    10179  }
    -
    10180  ++nextSuballocItem;
    -
    10181  }
    -
    10182  }
    -
    10183  }
    -
    10184 
    -
    10185  // All tests passed: Success. pOffset is already filled.
    -
    10186  return true;
    -
    10187 }
    -
    10188 
    -
    10189 void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item)
    -
    10190 {
    -
    10191  VMA_ASSERT(item != m_Suballocations.end());
    -
    10192  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10193 
    -
    10194  VmaSuballocationList::iterator nextItem = item;
    -
    10195  ++nextItem;
    -
    10196  VMA_ASSERT(nextItem != m_Suballocations.end());
    -
    10197  VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10198 
    -
    10199  item->size += nextItem->size;
    -
    10200  --m_FreeCount;
    -
    10201  m_Suballocations.erase(nextItem);
    +
    10116  // Size of this suballocation is too small for this request: Early return.
    +
    10117  if(suballoc.size < allocSize)
    +
    10118  {
    +
    10119  return false;
    +
    10120  }
    +
    10121 
    +
    10122  // Start from offset equal to beginning of this suballocation.
    +
    10123  *pOffset = suballoc.offset;
    +
    10124 
    +
    10125  // Apply VMA_DEBUG_MARGIN at the beginning.
    +
    10126  if(VMA_DEBUG_MARGIN > 0)
    +
    10127  {
    +
    10128  *pOffset += VMA_DEBUG_MARGIN;
    +
    10129  }
    +
    10130 
    +
    10131  // Apply alignment.
    +
    10132  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
    +
    10133 
    +
    10134  // Check previous suballocations for BufferImageGranularity conflicts.
    +
    10135  // Make bigger alignment if necessary.
    +
    10136  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
    +
    10137  {
    +
    10138  bool bufferImageGranularityConflict = false;
    +
    10139  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
    +
    10140  while(prevSuballocItem != m_Suballocations.cbegin())
    +
    10141  {
    +
    10142  --prevSuballocItem;
    +
    10143  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
    +
    10144  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
    +
    10145  {
    +
    10146  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    +
    10147  {
    +
    10148  bufferImageGranularityConflict = true;
    +
    10149  break;
    +
    10150  }
    +
    10151  }
    +
    10152  else
    +
    10153  // Already on previous page.
    +
    10154  break;
    +
    10155  }
    +
    10156  if(bufferImageGranularityConflict)
    +
    10157  {
    +
    10158  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
    +
    10159  }
    +
    10160  }
    +
    10161 
    +
    10162  // Calculate padding at the beginning based on current offset.
    +
    10163  const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
    +
    10164 
    +
    10165  // Calculate required margin at the end.
    +
    10166  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
    +
    10167 
    +
    10168  // Fail if requested size plus margin before and after is bigger than size of this suballocation.
    +
    10169  if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
    +
    10170  {
    +
    10171  return false;
    +
    10172  }
    +
    10173 
    +
    10174  // Check next suballocations for BufferImageGranularity conflicts.
    +
    10175  // If conflict exists, allocation cannot be made here.
    +
    10176  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
    +
    10177  {
    +
    10178  VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
    +
    10179  ++nextSuballocItem;
    +
    10180  while(nextSuballocItem != m_Suballocations.cend())
    +
    10181  {
    +
    10182  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
    +
    10183  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    +
    10184  {
    +
    10185  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    +
    10186  {
    +
    10187  return false;
    +
    10188  }
    +
    10189  }
    +
    10190  else
    +
    10191  {
    +
    10192  // Already on next page.
    +
    10193  break;
    +
    10194  }
    +
    10195  ++nextSuballocItem;
    +
    10196  }
    +
    10197  }
    +
    10198  }
    +
    10199 
    +
    10200  // All tests passed: Success. pOffset is already filled.
    +
    10201  return true;
    10202 }
    10203 
    -
    10204 VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
    +
    10204 void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item)
    10205 {
    -
    10206  // Change this suballocation to be marked as free.
    -
    10207  VmaSuballocation& suballoc = *suballocItem;
    -
    10208  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    10209  suballoc.hAllocation = VK_NULL_HANDLE;
    -
    10210 
    -
    10211  // Update totals.
    -
    10212  ++m_FreeCount;
    -
    10213  m_SumFreeSize += suballoc.size;
    -
    10214 
    -
    10215  // Merge with previous and/or next suballocation if it's also free.
    -
    10216  bool mergeWithNext = false;
    -
    10217  bool mergeWithPrev = false;
    +
    10206  VMA_ASSERT(item != m_Suballocations.end());
    +
    10207  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10208 
    +
    10209  VmaSuballocationList::iterator nextItem = item;
    +
    10210  ++nextItem;
    +
    10211  VMA_ASSERT(nextItem != m_Suballocations.end());
    +
    10212  VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10213 
    +
    10214  item->size += nextItem->size;
    +
    10215  --m_FreeCount;
    +
    10216  m_Suballocations.erase(nextItem);
    +
    10217 }
    10218 
    -
    10219  VmaSuballocationList::iterator nextItem = suballocItem;
    -
    10220  ++nextItem;
    -
    10221  if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
    -
    10222  {
    -
    10223  mergeWithNext = true;
    -
    10224  }
    +
    10219 VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
    +
    10220 {
    +
    10221  // Change this suballocation to be marked as free.
    +
    10222  VmaSuballocation& suballoc = *suballocItem;
    +
    10223  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    10224  suballoc.hAllocation = VK_NULL_HANDLE;
    10225 
    -
    10226  VmaSuballocationList::iterator prevItem = suballocItem;
    -
    10227  if(suballocItem != m_Suballocations.begin())
    -
    10228  {
    -
    10229  --prevItem;
    -
    10230  if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    10231  {
    -
    10232  mergeWithPrev = true;
    -
    10233  }
    -
    10234  }
    -
    10235 
    -
    10236  if(mergeWithNext)
    +
    10226  // Update totals.
    +
    10227  ++m_FreeCount;
    +
    10228  m_SumFreeSize += suballoc.size;
    +
    10229 
    +
    10230  // Merge with previous and/or next suballocation if it's also free.
    +
    10231  bool mergeWithNext = false;
    +
    10232  bool mergeWithPrev = false;
    +
    10233 
    +
    10234  VmaSuballocationList::iterator nextItem = suballocItem;
    +
    10235  ++nextItem;
    +
    10236  if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
    10237  {
    -
    10238  UnregisterFreeSuballocation(nextItem);
    -
    10239  MergeFreeWithNext(suballocItem);
    -
    10240  }
    -
    10241 
    -
    10242  if(mergeWithPrev)
    +
    10238  mergeWithNext = true;
    +
    10239  }
    +
    10240 
    +
    10241  VmaSuballocationList::iterator prevItem = suballocItem;
    +
    10242  if(suballocItem != m_Suballocations.begin())
    10243  {
    -
    10244  UnregisterFreeSuballocation(prevItem);
    -
    10245  MergeFreeWithNext(prevItem);
    -
    10246  RegisterFreeSuballocation(prevItem);
    -
    10247  return prevItem;
    -
    10248  }
    -
    10249  else
    -
    10250  {
    -
    10251  RegisterFreeSuballocation(suballocItem);
    -
    10252  return suballocItem;
    -
    10253  }
    -
    10254 }
    -
    10255 
    -
    10256 void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
    -
    10257 {
    -
    10258  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10259  VMA_ASSERT(item->size > 0);
    -
    10260 
    -
    10261  // You may want to enable this validation at the beginning or at the end of
    -
    10262  // this function, depending on what do you want to check.
    -
    10263  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    -
    10264 
    -
    10265  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    10266  {
    -
    10267  if(m_FreeSuballocationsBySize.empty())
    -
    10268  {
    -
    10269  m_FreeSuballocationsBySize.push_back(item);
    -
    10270  }
    -
    10271  else
    -
    10272  {
    -
    10273  VmaVectorInsertSorted<VmaSuballocationItemSizeLess>(m_FreeSuballocationsBySize, item);
    -
    10274  }
    -
    10275  }
    -
    10276 
    -
    10277  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    -
    10278 }
    +
    10244  --prevItem;
    +
    10245  if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    10246  {
    +
    10247  mergeWithPrev = true;
    +
    10248  }
    +
    10249  }
    +
    10250 
    +
    10251  if(mergeWithNext)
    +
    10252  {
    +
    10253  UnregisterFreeSuballocation(nextItem);
    +
    10254  MergeFreeWithNext(suballocItem);
    +
    10255  }
    +
    10256 
    +
    10257  if(mergeWithPrev)
    +
    10258  {
    +
    10259  UnregisterFreeSuballocation(prevItem);
    +
    10260  MergeFreeWithNext(prevItem);
    +
    10261  RegisterFreeSuballocation(prevItem);
    +
    10262  return prevItem;
    +
    10263  }
    +
    10264  else
    +
    10265  {
    +
    10266  RegisterFreeSuballocation(suballocItem);
    +
    10267  return suballocItem;
    +
    10268  }
    +
    10269 }
    +
    10270 
    +
    10271 void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
    +
    10272 {
    +
    10273  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10274  VMA_ASSERT(item->size > 0);
    +
    10275 
    +
    10276  // You may want to enable this validation at the beginning or at the end of
    +
    10277  // this function, depending on what do you want to check.
    +
    10278  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    10279 
    -
    10280 
    -
    10281 void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
    -
    10282 {
    -
    10283  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10284  VMA_ASSERT(item->size > 0);
    -
    10285 
    -
    10286  // You may want to enable this validation at the beginning or at the end of
    -
    10287  // this function, depending on what do you want to check.
    -
    10288  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    -
    10289 
    -
    10290  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    10291  {
    -
    10292  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    -
    10293  m_FreeSuballocationsBySize.data(),
    -
    10294  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
    -
    10295  item,
    -
    10296  VmaSuballocationItemSizeLess());
    -
    10297  for(size_t index = it - m_FreeSuballocationsBySize.data();
    -
    10298  index < m_FreeSuballocationsBySize.size();
    -
    10299  ++index)
    -
    10300  {
    -
    10301  if(m_FreeSuballocationsBySize[index] == item)
    -
    10302  {
    -
    10303  VmaVectorRemove(m_FreeSuballocationsBySize, index);
    -
    10304  return;
    -
    10305  }
    -
    10306  VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
    -
    10307  }
    -
    10308  VMA_ASSERT(0 && "Not found.");
    -
    10309  }
    -
    10310 
    -
    10311  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    -
    10312 }
    -
    10313 
    -
    10314 bool VmaBlockMetadata_Generic::IsBufferImageGranularityConflictPossible(
    -
    10315  VkDeviceSize bufferImageGranularity,
    -
    10316  VmaSuballocationType& inOutPrevSuballocType) const
    -
    10317 {
    -
    10318  if(bufferImageGranularity == 1 || IsEmpty())
    -
    10319  {
    -
    10320  return false;
    -
    10321  }
    -
    10322 
    -
    10323  VkDeviceSize minAlignment = VK_WHOLE_SIZE;
    -
    10324  bool typeConflictFound = false;
    -
    10325  for(const auto& suballoc : m_Suballocations)
    -
    10326  {
    -
    10327  const VmaSuballocationType suballocType = suballoc.type;
    -
    10328  if(suballocType != VMA_SUBALLOCATION_TYPE_FREE)
    -
    10329  {
    -
    10330  minAlignment = VMA_MIN(minAlignment, suballoc.hAllocation->GetAlignment());
    -
    10331  if(VmaIsBufferImageGranularityConflict(inOutPrevSuballocType, suballocType))
    -
    10332  {
    -
    10333  typeConflictFound = true;
    -
    10334  }
    -
    10335  inOutPrevSuballocType = suballocType;
    -
    10336  }
    -
    10337  }
    -
    10338 
    -
    10339  return typeConflictFound || minAlignment >= bufferImageGranularity;
    -
    10340 }
    -
    10341 
    -
    10343 // class VmaBlockMetadata_Linear
    -
    10344 
    -
    10345 VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(VmaAllocator hAllocator) :
    -
    10346  VmaBlockMetadata(hAllocator),
    -
    10347  m_SumFreeSize(0),
    -
    10348  m_Suballocations0(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    -
    10349  m_Suballocations1(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    -
    10350  m_1stVectorIndex(0),
    -
    10351  m_2ndVectorMode(SECOND_VECTOR_EMPTY),
    -
    10352  m_1stNullItemsBeginCount(0),
    -
    10353  m_1stNullItemsMiddleCount(0),
    -
    10354  m_2ndNullItemsCount(0)
    -
    10355 {
    -
    10356 }
    -
    10357 
    -
    10358 VmaBlockMetadata_Linear::~VmaBlockMetadata_Linear()
    -
    10359 {
    -
    10360 }
    -
    10361 
    -
    10362 void VmaBlockMetadata_Linear::Init(VkDeviceSize size)
    -
    10363 {
    -
    10364  VmaBlockMetadata::Init(size);
    -
    10365  m_SumFreeSize = size;
    -
    10366 }
    -
    10367 
    -
    10368 bool VmaBlockMetadata_Linear::Validate() const
    -
    10369 {
    -
    10370  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    10371  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10280  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    10281  {
    +
    10282  if(m_FreeSuballocationsBySize.empty())
    +
    10283  {
    +
    10284  m_FreeSuballocationsBySize.push_back(item);
    +
    10285  }
    +
    10286  else
    +
    10287  {
    +
    10288  VmaVectorInsertSorted<VmaSuballocationItemSizeLess>(m_FreeSuballocationsBySize, item);
    +
    10289  }
    +
    10290  }
    +
    10291 
    +
    10292  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    +
    10293 }
    +
    10294 
    +
    10295 
    +
    10296 void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
    +
    10297 {
    +
    10298  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10299  VMA_ASSERT(item->size > 0);
    +
    10300 
    +
    10301  // You may want to enable this validation at the beginning or at the end of
    +
    10302  // this function, depending on what do you want to check.
    +
    10303  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    +
    10304 
    +
    10305  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    10306  {
    +
    10307  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    +
    10308  m_FreeSuballocationsBySize.data(),
    +
    10309  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
    +
    10310  item,
    +
    10311  VmaSuballocationItemSizeLess());
    +
    10312  for(size_t index = it - m_FreeSuballocationsBySize.data();
    +
    10313  index < m_FreeSuballocationsBySize.size();
    +
    10314  ++index)
    +
    10315  {
    +
    10316  if(m_FreeSuballocationsBySize[index] == item)
    +
    10317  {
    +
    10318  VmaVectorRemove(m_FreeSuballocationsBySize, index);
    +
    10319  return;
    +
    10320  }
    +
    10321  VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
    +
    10322  }
    +
    10323  VMA_ASSERT(0 && "Not found.");
    +
    10324  }
    +
    10325 
    +
    10326  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
    +
    10327 }
    +
    10328 
    +
    10329 bool VmaBlockMetadata_Generic::IsBufferImageGranularityConflictPossible(
    +
    10330  VkDeviceSize bufferImageGranularity,
    +
    10331  VmaSuballocationType& inOutPrevSuballocType) const
    +
    10332 {
    +
    10333  if(bufferImageGranularity == 1 || IsEmpty())
    +
    10334  {
    +
    10335  return false;
    +
    10336  }
    +
    10337 
    +
    10338  VkDeviceSize minAlignment = VK_WHOLE_SIZE;
    +
    10339  bool typeConflictFound = false;
    +
    10340  for(const auto& suballoc : m_Suballocations)
    +
    10341  {
    +
    10342  const VmaSuballocationType suballocType = suballoc.type;
    +
    10343  if(suballocType != VMA_SUBALLOCATION_TYPE_FREE)
    +
    10344  {
    +
    10345  minAlignment = VMA_MIN(minAlignment, suballoc.hAllocation->GetAlignment());
    +
    10346  if(VmaIsBufferImageGranularityConflict(inOutPrevSuballocType, suballocType))
    +
    10347  {
    +
    10348  typeConflictFound = true;
    +
    10349  }
    +
    10350  inOutPrevSuballocType = suballocType;
    +
    10351  }
    +
    10352  }
    +
    10353 
    +
    10354  return typeConflictFound || minAlignment >= bufferImageGranularity;
    +
    10355 }
    +
    10356 
    +
    10358 // class VmaBlockMetadata_Linear
    +
    10359 
    +
    10360 VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(VmaAllocator hAllocator) :
    +
    10361  VmaBlockMetadata(hAllocator),
    +
    10362  m_SumFreeSize(0),
    +
    10363  m_Suballocations0(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    +
    10364  m_Suballocations1(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    +
    10365  m_1stVectorIndex(0),
    +
    10366  m_2ndVectorMode(SECOND_VECTOR_EMPTY),
    +
    10367  m_1stNullItemsBeginCount(0),
    +
    10368  m_1stNullItemsMiddleCount(0),
    +
    10369  m_2ndNullItemsCount(0)
    +
    10370 {
    +
    10371 }
    10372 
    -
    10373  VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
    -
    10374  VMA_VALIDATE(!suballocations1st.empty() ||
    -
    10375  suballocations2nd.empty() ||
    -
    10376  m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
    -
    10377 
    -
    10378  if(!suballocations1st.empty())
    -
    10379  {
    -
    10380  // Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
    -
    10381  VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].hAllocation != VK_NULL_HANDLE);
    -
    10382  // Null item at the end should be just pop_back().
    -
    10383  VMA_VALIDATE(suballocations1st.back().hAllocation != VK_NULL_HANDLE);
    -
    10384  }
    -
    10385  if(!suballocations2nd.empty())
    -
    10386  {
    -
    10387  // Null item at the end should be just pop_back().
    -
    10388  VMA_VALIDATE(suballocations2nd.back().hAllocation != VK_NULL_HANDLE);
    -
    10389  }
    -
    10390 
    -
    10391  VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
    -
    10392  VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
    -
    10393 
    -
    10394  VkDeviceSize sumUsedSize = 0;
    -
    10395  const size_t suballoc1stCount = suballocations1st.size();
    -
    10396  VkDeviceSize offset = VMA_DEBUG_MARGIN;
    -
    10397 
    -
    10398  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    10399  {
    -
    10400  const size_t suballoc2ndCount = suballocations2nd.size();
    -
    10401  size_t nullItem2ndCount = 0;
    -
    10402  for(size_t i = 0; i < suballoc2ndCount; ++i)
    -
    10403  {
    -
    10404  const VmaSuballocation& suballoc = suballocations2nd[i];
    -
    10405  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10406 
    -
    10407  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
    -
    10408  VMA_VALIDATE(suballoc.offset >= offset);
    -
    10409 
    -
    10410  if(!currFree)
    -
    10411  {
    -
    10412  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
    -
    10413  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
    -
    10414  sumUsedSize += suballoc.size;
    -
    10415  }
    -
    10416  else
    -
    10417  {
    -
    10418  ++nullItem2ndCount;
    -
    10419  }
    -
    10420 
    -
    10421  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
    -
    10422  }
    -
    10423 
    -
    10424  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
    -
    10425  }
    -
    10426 
    -
    10427  for(size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
    -
    10428  {
    -
    10429  const VmaSuballocation& suballoc = suballocations1st[i];
    -
    10430  VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE &&
    -
    10431  suballoc.hAllocation == VK_NULL_HANDLE);
    -
    10432  }
    -
    10433 
    -
    10434  size_t nullItem1stCount = m_1stNullItemsBeginCount;
    +
    10373 VmaBlockMetadata_Linear::~VmaBlockMetadata_Linear()
    +
    10374 {
    +
    10375 }
    +
    10376 
    +
    10377 void VmaBlockMetadata_Linear::Init(VkDeviceSize size)
    +
    10378 {
    +
    10379  VmaBlockMetadata::Init(size);
    +
    10380  m_SumFreeSize = size;
    +
    10381 }
    +
    10382 
    +
    10383 bool VmaBlockMetadata_Linear::Validate() const
    +
    10384 {
    +
    10385  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    10386  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10387 
    +
    10388  VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
    +
    10389  VMA_VALIDATE(!suballocations1st.empty() ||
    +
    10390  suballocations2nd.empty() ||
    +
    10391  m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
    +
    10392 
    +
    10393  if(!suballocations1st.empty())
    +
    10394  {
    +
    10395  // Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
    +
    10396  VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].hAllocation != VK_NULL_HANDLE);
    +
    10397  // Null item at the end should be just pop_back().
    +
    10398  VMA_VALIDATE(suballocations1st.back().hAllocation != VK_NULL_HANDLE);
    +
    10399  }
    +
    10400  if(!suballocations2nd.empty())
    +
    10401  {
    +
    10402  // Null item at the end should be just pop_back().
    +
    10403  VMA_VALIDATE(suballocations2nd.back().hAllocation != VK_NULL_HANDLE);
    +
    10404  }
    +
    10405 
    +
    10406  VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
    +
    10407  VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
    +
    10408 
    +
    10409  VkDeviceSize sumUsedSize = 0;
    +
    10410  const size_t suballoc1stCount = suballocations1st.size();
    +
    10411  VkDeviceSize offset = VMA_DEBUG_MARGIN;
    +
    10412 
    +
    10413  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    10414  {
    +
    10415  const size_t suballoc2ndCount = suballocations2nd.size();
    +
    10416  size_t nullItem2ndCount = 0;
    +
    10417  for(size_t i = 0; i < suballoc2ndCount; ++i)
    +
    10418  {
    +
    10419  const VmaSuballocation& suballoc = suballocations2nd[i];
    +
    10420  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10421 
    +
    10422  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
    +
    10423  VMA_VALIDATE(suballoc.offset >= offset);
    +
    10424 
    +
    10425  if(!currFree)
    +
    10426  {
    +
    10427  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
    +
    10428  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
    +
    10429  sumUsedSize += suballoc.size;
    +
    10430  }
    +
    10431  else
    +
    10432  {
    +
    10433  ++nullItem2ndCount;
    +
    10434  }
    10435 
    -
    10436  for(size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i)
    -
    10437  {
    -
    10438  const VmaSuballocation& suballoc = suballocations1st[i];
    -
    10439  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10440 
    -
    10441  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
    -
    10442  VMA_VALIDATE(suballoc.offset >= offset);
    -
    10443  VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
    -
    10444 
    -
    10445  if(!currFree)
    -
    10446  {
    -
    10447  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
    -
    10448  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
    -
    10449  sumUsedSize += suballoc.size;
    -
    10450  }
    -
    10451  else
    -
    10452  {
    -
    10453  ++nullItem1stCount;
    -
    10454  }
    +
    10436  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
    +
    10437  }
    +
    10438 
    +
    10439  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
    +
    10440  }
    +
    10441 
    +
    10442  for(size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
    +
    10443  {
    +
    10444  const VmaSuballocation& suballoc = suballocations1st[i];
    +
    10445  VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE &&
    +
    10446  suballoc.hAllocation == VK_NULL_HANDLE);
    +
    10447  }
    +
    10448 
    +
    10449  size_t nullItem1stCount = m_1stNullItemsBeginCount;
    +
    10450 
    +
    10451  for(size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i)
    +
    10452  {
    +
    10453  const VmaSuballocation& suballoc = suballocations1st[i];
    +
    10454  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    10455 
    -
    10456  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
    -
    10457  }
    -
    10458  VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
    +
    10456  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
    +
    10457  VMA_VALIDATE(suballoc.offset >= offset);
    +
    10458  VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
    10459 
    -
    10460  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    10461  {
    -
    10462  const size_t suballoc2ndCount = suballocations2nd.size();
    -
    10463  size_t nullItem2ndCount = 0;
    -
    10464  for(size_t i = suballoc2ndCount; i--; )
    -
    10465  {
    -
    10466  const VmaSuballocation& suballoc = suballocations2nd[i];
    -
    10467  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    -
    10468 
    -
    10469  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
    -
    10470  VMA_VALIDATE(suballoc.offset >= offset);
    -
    10471 
    -
    10472  if(!currFree)
    -
    10473  {
    -
    10474  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
    -
    10475  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
    -
    10476  sumUsedSize += suballoc.size;
    -
    10477  }
    -
    10478  else
    -
    10479  {
    -
    10480  ++nullItem2ndCount;
    -
    10481  }
    -
    10482 
    -
    10483  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
    -
    10484  }
    -
    10485 
    -
    10486  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
    -
    10487  }
    -
    10488 
    -
    10489  VMA_VALIDATE(offset <= GetSize());
    -
    10490  VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
    -
    10491 
    -
    10492  return true;
    -
    10493 }
    -
    10494 
    -
    10495 size_t VmaBlockMetadata_Linear::GetAllocationCount() const
    -
    10496 {
    -
    10497  return AccessSuballocations1st().size() - (m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount) +
    -
    10498  AccessSuballocations2nd().size() - m_2ndNullItemsCount;
    -
    10499 }
    +
    10460  if(!currFree)
    +
    10461  {
    +
    10462  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
    +
    10463  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
    +
    10464  sumUsedSize += suballoc.size;
    +
    10465  }
    +
    10466  else
    +
    10467  {
    +
    10468  ++nullItem1stCount;
    +
    10469  }
    +
    10470 
    +
    10471  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
    +
    10472  }
    +
    10473  VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
    +
    10474 
    +
    10475  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    10476  {
    +
    10477  const size_t suballoc2ndCount = suballocations2nd.size();
    +
    10478  size_t nullItem2ndCount = 0;
    +
    10479  for(size_t i = suballoc2ndCount; i--; )
    +
    10480  {
    +
    10481  const VmaSuballocation& suballoc = suballocations2nd[i];
    +
    10482  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    +
    10483 
    +
    10484  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
    +
    10485  VMA_VALIDATE(suballoc.offset >= offset);
    +
    10486 
    +
    10487  if(!currFree)
    +
    10488  {
    +
    10489  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
    +
    10490  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
    +
    10491  sumUsedSize += suballoc.size;
    +
    10492  }
    +
    10493  else
    +
    10494  {
    +
    10495  ++nullItem2ndCount;
    +
    10496  }
    +
    10497 
    +
    10498  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
    +
    10499  }
    10500 
    -
    10501 VkDeviceSize VmaBlockMetadata_Linear::GetUnusedRangeSizeMax() const
    -
    10502 {
    -
    10503  const VkDeviceSize size = GetSize();
    -
    10504 
    -
    10505  /*
    -
    10506  We don't consider gaps inside allocation vectors with freed allocations because
    -
    10507  they are not suitable for reuse in linear allocator. We consider only space that
    -
    10508  is available for new allocations.
    -
    10509  */
    -
    10510  if(IsEmpty())
    -
    10511  {
    -
    10512  return size;
    -
    10513  }
    -
    10514 
    -
    10515  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    10516 
    -
    10517  switch(m_2ndVectorMode)
    -
    10518  {
    -
    10519  case SECOND_VECTOR_EMPTY:
    -
    10520  /*
    -
    10521  Available space is after end of 1st, as well as before beginning of 1st (which
    -
    10522  would make it a ring buffer).
    -
    10523  */
    -
    10524  {
    -
    10525  const size_t suballocations1stCount = suballocations1st.size();
    -
    10526  VMA_ASSERT(suballocations1stCount > m_1stNullItemsBeginCount);
    -
    10527  const VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
    -
    10528  const VmaSuballocation& lastSuballoc = suballocations1st[suballocations1stCount - 1];
    -
    10529  return VMA_MAX(
    -
    10530  firstSuballoc.offset,
    -
    10531  size - (lastSuballoc.offset + lastSuballoc.size));
    -
    10532  }
    -
    10533  break;
    -
    10534 
    -
    10535  case SECOND_VECTOR_RING_BUFFER:
    -
    10536  /*
    -
    10537  Available space is only between end of 2nd and beginning of 1st.
    +
    10501  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
    +
    10502  }
    +
    10503 
    +
    10504  VMA_VALIDATE(offset <= GetSize());
    +
    10505  VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
    +
    10506 
    +
    10507  return true;
    +
    10508 }
    +
    10509 
    +
    10510 size_t VmaBlockMetadata_Linear::GetAllocationCount() const
    +
    10511 {
    +
    10512  return AccessSuballocations1st().size() - (m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount) +
    +
    10513  AccessSuballocations2nd().size() - m_2ndNullItemsCount;
    +
    10514 }
    +
    10515 
    +
    10516 VkDeviceSize VmaBlockMetadata_Linear::GetUnusedRangeSizeMax() const
    +
    10517 {
    +
    10518  const VkDeviceSize size = GetSize();
    +
    10519 
    +
    10520  /*
    +
    10521  We don't consider gaps inside allocation vectors with freed allocations because
    +
    10522  they are not suitable for reuse in linear allocator. We consider only space that
    +
    10523  is available for new allocations.
    +
    10524  */
    +
    10525  if(IsEmpty())
    +
    10526  {
    +
    10527  return size;
    +
    10528  }
    +
    10529 
    +
    10530  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    10531 
    +
    10532  switch(m_2ndVectorMode)
    +
    10533  {
    +
    10534  case SECOND_VECTOR_EMPTY:
    +
    10535  /*
    +
    10536  Available space is after end of 1st, as well as before beginning of 1st (which
    +
    10537  would make it a ring buffer).
    10538  */
    10539  {
    -
    10540  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    10541  const VmaSuballocation& lastSuballoc2nd = suballocations2nd.back();
    -
    10542  const VmaSuballocation& firstSuballoc1st = suballocations1st[m_1stNullItemsBeginCount];
    -
    10543  return firstSuballoc1st.offset - (lastSuballoc2nd.offset + lastSuballoc2nd.size);
    -
    10544  }
    -
    10545  break;
    -
    10546 
    -
    10547  case SECOND_VECTOR_DOUBLE_STACK:
    -
    10548  /*
    -
    10549  Available space is only between end of 1st and top of 2nd.
    -
    10550  */
    -
    10551  {
    -
    10552  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    10553  const VmaSuballocation& topSuballoc2nd = suballocations2nd.back();
    -
    10554  const VmaSuballocation& lastSuballoc1st = suballocations1st.back();
    -
    10555  return topSuballoc2nd.offset - (lastSuballoc1st.offset + lastSuballoc1st.size);
    -
    10556  }
    -
    10557  break;
    -
    10558 
    -
    10559  default:
    -
    10560  VMA_ASSERT(0);
    -
    10561  return 0;
    -
    10562  }
    -
    10563 }
    -
    10564 
    -
    10565 void VmaBlockMetadata_Linear::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
    -
    10566 {
    -
    10567  const VkDeviceSize size = GetSize();
    -
    10568  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    10569  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    10570  const size_t suballoc1stCount = suballocations1st.size();
    -
    10571  const size_t suballoc2ndCount = suballocations2nd.size();
    -
    10572 
    -
    10573  outInfo.blockCount = 1;
    -
    10574  outInfo.allocationCount = (uint32_t)GetAllocationCount();
    -
    10575  outInfo.unusedRangeCount = 0;
    -
    10576  outInfo.usedBytes = 0;
    -
    10577  outInfo.allocationSizeMin = UINT64_MAX;
    -
    10578  outInfo.allocationSizeMax = 0;
    -
    10579  outInfo.unusedRangeSizeMin = UINT64_MAX;
    -
    10580  outInfo.unusedRangeSizeMax = 0;
    -
    10581 
    -
    10582  VkDeviceSize lastOffset = 0;
    -
    10583 
    -
    10584  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    10585  {
    -
    10586  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    -
    10587  size_t nextAlloc2ndIndex = 0;
    -
    10588  while(lastOffset < freeSpace2ndTo1stEnd)
    -
    10589  {
    -
    10590  // Find next non-null allocation or move nextAllocIndex to the end.
    -
    10591  while(nextAlloc2ndIndex < suballoc2ndCount &&
    -
    10592  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    10593  {
    -
    10594  ++nextAlloc2ndIndex;
    -
    10595  }
    +
    10540  const size_t suballocations1stCount = suballocations1st.size();
    +
    10541  VMA_ASSERT(suballocations1stCount > m_1stNullItemsBeginCount);
    +
    10542  const VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
    +
    10543  const VmaSuballocation& lastSuballoc = suballocations1st[suballocations1stCount - 1];
    +
    10544  return VMA_MAX(
    +
    10545  firstSuballoc.offset,
    +
    10546  size - (lastSuballoc.offset + lastSuballoc.size));
    +
    10547  }
    +
    10548  break;
    +
    10549 
    +
    10550  case SECOND_VECTOR_RING_BUFFER:
    +
    10551  /*
    +
    10552  Available space is only between end of 2nd and beginning of 1st.
    +
    10553  */
    +
    10554  {
    +
    10555  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10556  const VmaSuballocation& lastSuballoc2nd = suballocations2nd.back();
    +
    10557  const VmaSuballocation& firstSuballoc1st = suballocations1st[m_1stNullItemsBeginCount];
    +
    10558  return firstSuballoc1st.offset - (lastSuballoc2nd.offset + lastSuballoc2nd.size);
    +
    10559  }
    +
    10560  break;
    +
    10561 
    +
    10562  case SECOND_VECTOR_DOUBLE_STACK:
    +
    10563  /*
    +
    10564  Available space is only between end of 1st and top of 2nd.
    +
    10565  */
    +
    10566  {
    +
    10567  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10568  const VmaSuballocation& topSuballoc2nd = suballocations2nd.back();
    +
    10569  const VmaSuballocation& lastSuballoc1st = suballocations1st.back();
    +
    10570  return topSuballoc2nd.offset - (lastSuballoc1st.offset + lastSuballoc1st.size);
    +
    10571  }
    +
    10572  break;
    +
    10573 
    +
    10574  default:
    +
    10575  VMA_ASSERT(0);
    +
    10576  return 0;
    +
    10577  }
    +
    10578 }
    +
    10579 
    +
    10580 void VmaBlockMetadata_Linear::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
    +
    10581 {
    +
    10582  const VkDeviceSize size = GetSize();
    +
    10583  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    10584  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10585  const size_t suballoc1stCount = suballocations1st.size();
    +
    10586  const size_t suballoc2ndCount = suballocations2nd.size();
    +
    10587 
    +
    10588  outInfo.blockCount = 1;
    +
    10589  outInfo.allocationCount = (uint32_t)GetAllocationCount();
    +
    10590  outInfo.unusedRangeCount = 0;
    +
    10591  outInfo.usedBytes = 0;
    +
    10592  outInfo.allocationSizeMin = UINT64_MAX;
    +
    10593  outInfo.allocationSizeMax = 0;
    +
    10594  outInfo.unusedRangeSizeMin = UINT64_MAX;
    +
    10595  outInfo.unusedRangeSizeMax = 0;
    10596 
    -
    10597  // Found non-null allocation.
    -
    10598  if(nextAlloc2ndIndex < suballoc2ndCount)
    -
    10599  {
    -
    10600  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    10601 
    -
    10602  // 1. Process free space before this allocation.
    -
    10603  if(lastOffset < suballoc.offset)
    -
    10604  {
    -
    10605  // There is free space from lastOffset to suballoc.offset.
    -
    10606  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    10607  ++outInfo.unusedRangeCount;
    -
    10608  outInfo.unusedBytes += unusedRangeSize;
    -
    10609  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    10610  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    10611  }
    -
    10612 
    -
    10613  // 2. Process this allocation.
    -
    10614  // There is allocation with suballoc.offset, suballoc.size.
    -
    10615  outInfo.usedBytes += suballoc.size;
    -
    10616  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    -
    10617  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
    -
    10618 
    -
    10619  // 3. Prepare for next iteration.
    -
    10620  lastOffset = suballoc.offset + suballoc.size;
    -
    10621  ++nextAlloc2ndIndex;
    -
    10622  }
    -
    10623  // We are at the end.
    -
    10624  else
    -
    10625  {
    -
    10626  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    -
    10627  if(lastOffset < freeSpace2ndTo1stEnd)
    -
    10628  {
    -
    10629  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
    -
    10630  ++outInfo.unusedRangeCount;
    -
    10631  outInfo.unusedBytes += unusedRangeSize;
    -
    10632  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    10633  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    10634  }
    -
    10635 
    -
    10636  // End of loop.
    -
    10637  lastOffset = freeSpace2ndTo1stEnd;
    -
    10638  }
    -
    10639  }
    -
    10640  }
    -
    10641 
    -
    10642  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
    -
    10643  const VkDeviceSize freeSpace1stTo2ndEnd =
    -
    10644  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
    -
    10645  while(lastOffset < freeSpace1stTo2ndEnd)
    -
    10646  {
    -
    10647  // Find next non-null allocation or move nextAllocIndex to the end.
    -
    10648  while(nextAlloc1stIndex < suballoc1stCount &&
    -
    10649  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    -
    10650  {
    -
    10651  ++nextAlloc1stIndex;
    -
    10652  }
    -
    10653 
    -
    10654  // Found non-null allocation.
    -
    10655  if(nextAlloc1stIndex < suballoc1stCount)
    -
    10656  {
    -
    10657  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    -
    10658 
    -
    10659  // 1. Process free space before this allocation.
    -
    10660  if(lastOffset < suballoc.offset)
    -
    10661  {
    -
    10662  // There is free space from lastOffset to suballoc.offset.
    -
    10663  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    10664  ++outInfo.unusedRangeCount;
    -
    10665  outInfo.unusedBytes += unusedRangeSize;
    -
    10666  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    10667  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    10668  }
    -
    10669 
    -
    10670  // 2. Process this allocation.
    -
    10671  // There is allocation with suballoc.offset, suballoc.size.
    -
    10672  outInfo.usedBytes += suballoc.size;
    -
    10673  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    -
    10674  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
    -
    10675 
    -
    10676  // 3. Prepare for next iteration.
    -
    10677  lastOffset = suballoc.offset + suballoc.size;
    -
    10678  ++nextAlloc1stIndex;
    -
    10679  }
    -
    10680  // We are at the end.
    -
    10681  else
    -
    10682  {
    -
    10683  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    -
    10684  if(lastOffset < freeSpace1stTo2ndEnd)
    -
    10685  {
    -
    10686  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
    -
    10687  ++outInfo.unusedRangeCount;
    -
    10688  outInfo.unusedBytes += unusedRangeSize;
    -
    10689  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    10690  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    10691  }
    -
    10692 
    -
    10693  // End of loop.
    -
    10694  lastOffset = freeSpace1stTo2ndEnd;
    -
    10695  }
    -
    10696  }
    -
    10697 
    -
    10698  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    10699  {
    -
    10700  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    -
    10701  while(lastOffset < size)
    -
    10702  {
    -
    10703  // Find next non-null allocation or move nextAllocIndex to the end.
    -
    10704  while(nextAlloc2ndIndex != SIZE_MAX &&
    -
    10705  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    10706  {
    -
    10707  --nextAlloc2ndIndex;
    -
    10708  }
    -
    10709 
    -
    10710  // Found non-null allocation.
    -
    10711  if(nextAlloc2ndIndex != SIZE_MAX)
    -
    10712  {
    -
    10713  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    10714 
    -
    10715  // 1. Process free space before this allocation.
    -
    10716  if(lastOffset < suballoc.offset)
    -
    10717  {
    -
    10718  // There is free space from lastOffset to suballoc.offset.
    -
    10719  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    10720  ++outInfo.unusedRangeCount;
    -
    10721  outInfo.unusedBytes += unusedRangeSize;
    -
    10722  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    10723  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    10724  }
    -
    10725 
    -
    10726  // 2. Process this allocation.
    -
    10727  // There is allocation with suballoc.offset, suballoc.size.
    -
    10728  outInfo.usedBytes += suballoc.size;
    -
    10729  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    -
    10730  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
    -
    10731 
    -
    10732  // 3. Prepare for next iteration.
    -
    10733  lastOffset = suballoc.offset + suballoc.size;
    -
    10734  --nextAlloc2ndIndex;
    -
    10735  }
    -
    10736  // We are at the end.
    -
    10737  else
    -
    10738  {
    -
    10739  // There is free space from lastOffset to size.
    -
    10740  if(lastOffset < size)
    -
    10741  {
    -
    10742  const VkDeviceSize unusedRangeSize = size - lastOffset;
    -
    10743  ++outInfo.unusedRangeCount;
    -
    10744  outInfo.unusedBytes += unusedRangeSize;
    -
    10745  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    10746  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    10747  }
    -
    10748 
    -
    10749  // End of loop.
    -
    10750  lastOffset = size;
    -
    10751  }
    -
    10752  }
    -
    10753  }
    -
    10754 
    -
    10755  outInfo.unusedBytes = size - outInfo.usedBytes;
    -
    10756 }
    -
    10757 
    -
    10758 void VmaBlockMetadata_Linear::AddPoolStats(VmaPoolStats& inoutStats) const
    -
    10759 {
    -
    10760  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    10761  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    10762  const VkDeviceSize size = GetSize();
    -
    10763  const size_t suballoc1stCount = suballocations1st.size();
    -
    10764  const size_t suballoc2ndCount = suballocations2nd.size();
    -
    10765 
    -
    10766  inoutStats.size += size;
    -
    10767 
    -
    10768  VkDeviceSize lastOffset = 0;
    +
    10597  VkDeviceSize lastOffset = 0;
    +
    10598 
    +
    10599  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    10600  {
    +
    10601  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    +
    10602  size_t nextAlloc2ndIndex = 0;
    +
    10603  while(lastOffset < freeSpace2ndTo1stEnd)
    +
    10604  {
    +
    10605  // Find next non-null allocation or move nextAllocIndex to the end.
    +
    10606  while(nextAlloc2ndIndex < suballoc2ndCount &&
    +
    10607  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    10608  {
    +
    10609  ++nextAlloc2ndIndex;
    +
    10610  }
    +
    10611 
    +
    10612  // Found non-null allocation.
    +
    10613  if(nextAlloc2ndIndex < suballoc2ndCount)
    +
    10614  {
    +
    10615  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    10616 
    +
    10617  // 1. Process free space before this allocation.
    +
    10618  if(lastOffset < suballoc.offset)
    +
    10619  {
    +
    10620  // There is free space from lastOffset to suballoc.offset.
    +
    10621  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    10622  ++outInfo.unusedRangeCount;
    +
    10623  outInfo.unusedBytes += unusedRangeSize;
    +
    10624  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    10625  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    10626  }
    +
    10627 
    +
    10628  // 2. Process this allocation.
    +
    10629  // There is allocation with suballoc.offset, suballoc.size.
    +
    10630  outInfo.usedBytes += suballoc.size;
    +
    10631  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    +
    10632  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
    +
    10633 
    +
    10634  // 3. Prepare for next iteration.
    +
    10635  lastOffset = suballoc.offset + suballoc.size;
    +
    10636  ++nextAlloc2ndIndex;
    +
    10637  }
    +
    10638  // We are at the end.
    +
    10639  else
    +
    10640  {
    +
    10641  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    +
    10642  if(lastOffset < freeSpace2ndTo1stEnd)
    +
    10643  {
    +
    10644  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
    +
    10645  ++outInfo.unusedRangeCount;
    +
    10646  outInfo.unusedBytes += unusedRangeSize;
    +
    10647  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    10648  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    10649  }
    +
    10650 
    +
    10651  // End of loop.
    +
    10652  lastOffset = freeSpace2ndTo1stEnd;
    +
    10653  }
    +
    10654  }
    +
    10655  }
    +
    10656 
    +
    10657  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
    +
    10658  const VkDeviceSize freeSpace1stTo2ndEnd =
    +
    10659  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
    +
    10660  while(lastOffset < freeSpace1stTo2ndEnd)
    +
    10661  {
    +
    10662  // Find next non-null allocation or move nextAllocIndex to the end.
    +
    10663  while(nextAlloc1stIndex < suballoc1stCount &&
    +
    10664  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    +
    10665  {
    +
    10666  ++nextAlloc1stIndex;
    +
    10667  }
    +
    10668 
    +
    10669  // Found non-null allocation.
    +
    10670  if(nextAlloc1stIndex < suballoc1stCount)
    +
    10671  {
    +
    10672  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    +
    10673 
    +
    10674  // 1. Process free space before this allocation.
    +
    10675  if(lastOffset < suballoc.offset)
    +
    10676  {
    +
    10677  // There is free space from lastOffset to suballoc.offset.
    +
    10678  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    10679  ++outInfo.unusedRangeCount;
    +
    10680  outInfo.unusedBytes += unusedRangeSize;
    +
    10681  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    10682  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    10683  }
    +
    10684 
    +
    10685  // 2. Process this allocation.
    +
    10686  // There is allocation with suballoc.offset, suballoc.size.
    +
    10687  outInfo.usedBytes += suballoc.size;
    +
    10688  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    +
    10689  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
    +
    10690 
    +
    10691  // 3. Prepare for next iteration.
    +
    10692  lastOffset = suballoc.offset + suballoc.size;
    +
    10693  ++nextAlloc1stIndex;
    +
    10694  }
    +
    10695  // We are at the end.
    +
    10696  else
    +
    10697  {
    +
    10698  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    +
    10699  if(lastOffset < freeSpace1stTo2ndEnd)
    +
    10700  {
    +
    10701  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
    +
    10702  ++outInfo.unusedRangeCount;
    +
    10703  outInfo.unusedBytes += unusedRangeSize;
    +
    10704  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    10705  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    10706  }
    +
    10707 
    +
    10708  // End of loop.
    +
    10709  lastOffset = freeSpace1stTo2ndEnd;
    +
    10710  }
    +
    10711  }
    +
    10712 
    +
    10713  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    10714  {
    +
    10715  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    +
    10716  while(lastOffset < size)
    +
    10717  {
    +
    10718  // Find next non-null allocation or move nextAllocIndex to the end.
    +
    10719  while(nextAlloc2ndIndex != SIZE_MAX &&
    +
    10720  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    10721  {
    +
    10722  --nextAlloc2ndIndex;
    +
    10723  }
    +
    10724 
    +
    10725  // Found non-null allocation.
    +
    10726  if(nextAlloc2ndIndex != SIZE_MAX)
    +
    10727  {
    +
    10728  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    10729 
    +
    10730  // 1. Process free space before this allocation.
    +
    10731  if(lastOffset < suballoc.offset)
    +
    10732  {
    +
    10733  // There is free space from lastOffset to suballoc.offset.
    +
    10734  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    10735  ++outInfo.unusedRangeCount;
    +
    10736  outInfo.unusedBytes += unusedRangeSize;
    +
    10737  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    10738  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    10739  }
    +
    10740 
    +
    10741  // 2. Process this allocation.
    +
    10742  // There is allocation with suballoc.offset, suballoc.size.
    +
    10743  outInfo.usedBytes += suballoc.size;
    +
    10744  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
    +
    10745  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
    +
    10746 
    +
    10747  // 3. Prepare for next iteration.
    +
    10748  lastOffset = suballoc.offset + suballoc.size;
    +
    10749  --nextAlloc2ndIndex;
    +
    10750  }
    +
    10751  // We are at the end.
    +
    10752  else
    +
    10753  {
    +
    10754  // There is free space from lastOffset to size.
    +
    10755  if(lastOffset < size)
    +
    10756  {
    +
    10757  const VkDeviceSize unusedRangeSize = size - lastOffset;
    +
    10758  ++outInfo.unusedRangeCount;
    +
    10759  outInfo.unusedBytes += unusedRangeSize;
    +
    10760  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    10761  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    10762  }
    +
    10763 
    +
    10764  // End of loop.
    +
    10765  lastOffset = size;
    +
    10766  }
    +
    10767  }
    +
    10768  }
    10769 
    -
    10770  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    10771  {
    -
    10772  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    -
    10773  size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount;
    -
    10774  while(lastOffset < freeSpace2ndTo1stEnd)
    -
    10775  {
    -
    10776  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    -
    10777  while(nextAlloc2ndIndex < suballoc2ndCount &&
    -
    10778  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    10779  {
    -
    10780  ++nextAlloc2ndIndex;
    -
    10781  }
    +
    10770  outInfo.unusedBytes = size - outInfo.usedBytes;
    +
    10771 }
    +
    10772 
    +
    10773 void VmaBlockMetadata_Linear::AddPoolStats(VmaPoolStats& inoutStats) const
    +
    10774 {
    +
    10775  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    10776  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10777  const VkDeviceSize size = GetSize();
    +
    10778  const size_t suballoc1stCount = suballocations1st.size();
    +
    10779  const size_t suballoc2ndCount = suballocations2nd.size();
    +
    10780 
    +
    10781  inoutStats.size += size;
    10782 
    -
    10783  // Found non-null allocation.
    -
    10784  if(nextAlloc2ndIndex < suballoc2ndCount)
    -
    10785  {
    -
    10786  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    10787 
    -
    10788  // 1. Process free space before this allocation.
    -
    10789  if(lastOffset < suballoc.offset)
    -
    10790  {
    -
    10791  // There is free space from lastOffset to suballoc.offset.
    -
    10792  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    10793  inoutStats.unusedSize += unusedRangeSize;
    -
    10794  ++inoutStats.unusedRangeCount;
    -
    10795  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    -
    10796  }
    +
    10783  VkDeviceSize lastOffset = 0;
    +
    10784 
    +
    10785  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    10786  {
    +
    10787  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    +
    10788  size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount;
    +
    10789  while(lastOffset < freeSpace2ndTo1stEnd)
    +
    10790  {
    +
    10791  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    +
    10792  while(nextAlloc2ndIndex < suballoc2ndCount &&
    +
    10793  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    10794  {
    +
    10795  ++nextAlloc2ndIndex;
    +
    10796  }
    10797 
    -
    10798  // 2. Process this allocation.
    -
    10799  // There is allocation with suballoc.offset, suballoc.size.
    -
    10800  ++inoutStats.allocationCount;
    -
    10801 
    -
    10802  // 3. Prepare for next iteration.
    -
    10803  lastOffset = suballoc.offset + suballoc.size;
    -
    10804  ++nextAlloc2ndIndex;
    -
    10805  }
    -
    10806  // We are at the end.
    -
    10807  else
    -
    10808  {
    -
    10809  if(lastOffset < freeSpace2ndTo1stEnd)
    -
    10810  {
    -
    10811  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    -
    10812  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
    -
    10813  inoutStats.unusedSize += unusedRangeSize;
    -
    10814  ++inoutStats.unusedRangeCount;
    -
    10815  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    -
    10816  }
    -
    10817 
    -
    10818  // End of loop.
    -
    10819  lastOffset = freeSpace2ndTo1stEnd;
    +
    10798  // Found non-null allocation.
    +
    10799  if(nextAlloc2ndIndex < suballoc2ndCount)
    +
    10800  {
    +
    10801  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    10802 
    +
    10803  // 1. Process free space before this allocation.
    +
    10804  if(lastOffset < suballoc.offset)
    +
    10805  {
    +
    10806  // There is free space from lastOffset to suballoc.offset.
    +
    10807  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    10808  inoutStats.unusedSize += unusedRangeSize;
    +
    10809  ++inoutStats.unusedRangeCount;
    +
    10810  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    +
    10811  }
    +
    10812 
    +
    10813  // 2. Process this allocation.
    +
    10814  // There is allocation with suballoc.offset, suballoc.size.
    +
    10815  ++inoutStats.allocationCount;
    +
    10816 
    +
    10817  // 3. Prepare for next iteration.
    +
    10818  lastOffset = suballoc.offset + suballoc.size;
    +
    10819  ++nextAlloc2ndIndex;
    10820  }
    -
    10821  }
    -
    10822  }
    -
    10823 
    -
    10824  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
    -
    10825  const VkDeviceSize freeSpace1stTo2ndEnd =
    -
    10826  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
    -
    10827  while(lastOffset < freeSpace1stTo2ndEnd)
    -
    10828  {
    -
    10829  // Find next non-null allocation or move nextAllocIndex to the end.
    -
    10830  while(nextAlloc1stIndex < suballoc1stCount &&
    -
    10831  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    -
    10832  {
    -
    10833  ++nextAlloc1stIndex;
    -
    10834  }
    -
    10835 
    -
    10836  // Found non-null allocation.
    -
    10837  if(nextAlloc1stIndex < suballoc1stCount)
    -
    10838  {
    -
    10839  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    -
    10840 
    -
    10841  // 1. Process free space before this allocation.
    -
    10842  if(lastOffset < suballoc.offset)
    -
    10843  {
    -
    10844  // There is free space from lastOffset to suballoc.offset.
    -
    10845  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    10846  inoutStats.unusedSize += unusedRangeSize;
    -
    10847  ++inoutStats.unusedRangeCount;
    -
    10848  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    -
    10849  }
    +
    10821  // We are at the end.
    +
    10822  else
    +
    10823  {
    +
    10824  if(lastOffset < freeSpace2ndTo1stEnd)
    +
    10825  {
    +
    10826  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    +
    10827  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
    +
    10828  inoutStats.unusedSize += unusedRangeSize;
    +
    10829  ++inoutStats.unusedRangeCount;
    +
    10830  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    +
    10831  }
    +
    10832 
    +
    10833  // End of loop.
    +
    10834  lastOffset = freeSpace2ndTo1stEnd;
    +
    10835  }
    +
    10836  }
    +
    10837  }
    +
    10838 
    +
    10839  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
    +
    10840  const VkDeviceSize freeSpace1stTo2ndEnd =
    +
    10841  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
    +
    10842  while(lastOffset < freeSpace1stTo2ndEnd)
    +
    10843  {
    +
    10844  // Find next non-null allocation or move nextAllocIndex to the end.
    +
    10845  while(nextAlloc1stIndex < suballoc1stCount &&
    +
    10846  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    +
    10847  {
    +
    10848  ++nextAlloc1stIndex;
    +
    10849  }
    10850 
    -
    10851  // 2. Process this allocation.
    -
    10852  // There is allocation with suballoc.offset, suballoc.size.
    -
    10853  ++inoutStats.allocationCount;
    -
    10854 
    -
    10855  // 3. Prepare for next iteration.
    -
    10856  lastOffset = suballoc.offset + suballoc.size;
    -
    10857  ++nextAlloc1stIndex;
    -
    10858  }
    -
    10859  // We are at the end.
    -
    10860  else
    -
    10861  {
    -
    10862  if(lastOffset < freeSpace1stTo2ndEnd)
    -
    10863  {
    -
    10864  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    -
    10865  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
    -
    10866  inoutStats.unusedSize += unusedRangeSize;
    -
    10867  ++inoutStats.unusedRangeCount;
    -
    10868  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    -
    10869  }
    -
    10870 
    -
    10871  // End of loop.
    -
    10872  lastOffset = freeSpace1stTo2ndEnd;
    +
    10851  // Found non-null allocation.
    +
    10852  if(nextAlloc1stIndex < suballoc1stCount)
    +
    10853  {
    +
    10854  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    +
    10855 
    +
    10856  // 1. Process free space before this allocation.
    +
    10857  if(lastOffset < suballoc.offset)
    +
    10858  {
    +
    10859  // There is free space from lastOffset to suballoc.offset.
    +
    10860  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    10861  inoutStats.unusedSize += unusedRangeSize;
    +
    10862  ++inoutStats.unusedRangeCount;
    +
    10863  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    +
    10864  }
    +
    10865 
    +
    10866  // 2. Process this allocation.
    +
    10867  // There is allocation with suballoc.offset, suballoc.size.
    +
    10868  ++inoutStats.allocationCount;
    +
    10869 
    +
    10870  // 3. Prepare for next iteration.
    +
    10871  lastOffset = suballoc.offset + suballoc.size;
    +
    10872  ++nextAlloc1stIndex;
    10873  }
    -
    10874  }
    -
    10875 
    -
    10876  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    10877  {
    -
    10878  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    -
    10879  while(lastOffset < size)
    -
    10880  {
    -
    10881  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    -
    10882  while(nextAlloc2ndIndex != SIZE_MAX &&
    -
    10883  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    10884  {
    -
    10885  --nextAlloc2ndIndex;
    -
    10886  }
    -
    10887 
    -
    10888  // Found non-null allocation.
    -
    10889  if(nextAlloc2ndIndex != SIZE_MAX)
    -
    10890  {
    -
    10891  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    10892 
    -
    10893  // 1. Process free space before this allocation.
    -
    10894  if(lastOffset < suballoc.offset)
    -
    10895  {
    -
    10896  // There is free space from lastOffset to suballoc.offset.
    -
    10897  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    10898  inoutStats.unusedSize += unusedRangeSize;
    -
    10899  ++inoutStats.unusedRangeCount;
    -
    10900  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    -
    10901  }
    +
    10874  // We are at the end.
    +
    10875  else
    +
    10876  {
    +
    10877  if(lastOffset < freeSpace1stTo2ndEnd)
    +
    10878  {
    +
    10879  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    +
    10880  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
    +
    10881  inoutStats.unusedSize += unusedRangeSize;
    +
    10882  ++inoutStats.unusedRangeCount;
    +
    10883  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    +
    10884  }
    +
    10885 
    +
    10886  // End of loop.
    +
    10887  lastOffset = freeSpace1stTo2ndEnd;
    +
    10888  }
    +
    10889  }
    +
    10890 
    +
    10891  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    10892  {
    +
    10893  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    +
    10894  while(lastOffset < size)
    +
    10895  {
    +
    10896  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    +
    10897  while(nextAlloc2ndIndex != SIZE_MAX &&
    +
    10898  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    10899  {
    +
    10900  --nextAlloc2ndIndex;
    +
    10901  }
    10902 
    -
    10903  // 2. Process this allocation.
    -
    10904  // There is allocation with suballoc.offset, suballoc.size.
    -
    10905  ++inoutStats.allocationCount;
    -
    10906 
    -
    10907  // 3. Prepare for next iteration.
    -
    10908  lastOffset = suballoc.offset + suballoc.size;
    -
    10909  --nextAlloc2ndIndex;
    -
    10910  }
    -
    10911  // We are at the end.
    -
    10912  else
    -
    10913  {
    -
    10914  if(lastOffset < size)
    -
    10915  {
    -
    10916  // There is free space from lastOffset to size.
    -
    10917  const VkDeviceSize unusedRangeSize = size - lastOffset;
    -
    10918  inoutStats.unusedSize += unusedRangeSize;
    -
    10919  ++inoutStats.unusedRangeCount;
    -
    10920  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    -
    10921  }
    -
    10922 
    -
    10923  // End of loop.
    -
    10924  lastOffset = size;
    +
    10903  // Found non-null allocation.
    +
    10904  if(nextAlloc2ndIndex != SIZE_MAX)
    +
    10905  {
    +
    10906  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    10907 
    +
    10908  // 1. Process free space before this allocation.
    +
    10909  if(lastOffset < suballoc.offset)
    +
    10910  {
    +
    10911  // There is free space from lastOffset to suballoc.offset.
    +
    10912  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    10913  inoutStats.unusedSize += unusedRangeSize;
    +
    10914  ++inoutStats.unusedRangeCount;
    +
    10915  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    +
    10916  }
    +
    10917 
    +
    10918  // 2. Process this allocation.
    +
    10919  // There is allocation with suballoc.offset, suballoc.size.
    +
    10920  ++inoutStats.allocationCount;
    +
    10921 
    +
    10922  // 3. Prepare for next iteration.
    +
    10923  lastOffset = suballoc.offset + suballoc.size;
    +
    10924  --nextAlloc2ndIndex;
    10925  }
    -
    10926  }
    -
    10927  }
    -
    10928 }
    -
    10929 
    -
    10930 #if VMA_STATS_STRING_ENABLED
    -
    10931 void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
    -
    10932 {
    -
    10933  const VkDeviceSize size = GetSize();
    -
    10934  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    10935  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    10936  const size_t suballoc1stCount = suballocations1st.size();
    -
    10937  const size_t suballoc2ndCount = suballocations2nd.size();
    -
    10938 
    -
    10939  // FIRST PASS
    -
    10940 
    -
    10941  size_t unusedRangeCount = 0;
    -
    10942  VkDeviceSize usedBytes = 0;
    -
    10943 
    -
    10944  VkDeviceSize lastOffset = 0;
    -
    10945 
    -
    10946  size_t alloc2ndCount = 0;
    -
    10947  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    10948  {
    -
    10949  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    -
    10950  size_t nextAlloc2ndIndex = 0;
    -
    10951  while(lastOffset < freeSpace2ndTo1stEnd)
    -
    10952  {
    -
    10953  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    -
    10954  while(nextAlloc2ndIndex < suballoc2ndCount &&
    -
    10955  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    10956  {
    -
    10957  ++nextAlloc2ndIndex;
    -
    10958  }
    -
    10959 
    -
    10960  // Found non-null allocation.
    -
    10961  if(nextAlloc2ndIndex < suballoc2ndCount)
    -
    10962  {
    -
    10963  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    10964 
    -
    10965  // 1. Process free space before this allocation.
    -
    10966  if(lastOffset < suballoc.offset)
    -
    10967  {
    -
    10968  // There is free space from lastOffset to suballoc.offset.
    -
    10969  ++unusedRangeCount;
    -
    10970  }
    -
    10971 
    -
    10972  // 2. Process this allocation.
    -
    10973  // There is allocation with suballoc.offset, suballoc.size.
    -
    10974  ++alloc2ndCount;
    -
    10975  usedBytes += suballoc.size;
    -
    10976 
    -
    10977  // 3. Prepare for next iteration.
    -
    10978  lastOffset = suballoc.offset + suballoc.size;
    -
    10979  ++nextAlloc2ndIndex;
    -
    10980  }
    -
    10981  // We are at the end.
    -
    10982  else
    -
    10983  {
    -
    10984  if(lastOffset < freeSpace2ndTo1stEnd)
    -
    10985  {
    -
    10986  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    -
    10987  ++unusedRangeCount;
    -
    10988  }
    -
    10989 
    -
    10990  // End of loop.
    -
    10991  lastOffset = freeSpace2ndTo1stEnd;
    -
    10992  }
    -
    10993  }
    -
    10994  }
    -
    10995 
    -
    10996  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
    -
    10997  size_t alloc1stCount = 0;
    -
    10998  const VkDeviceSize freeSpace1stTo2ndEnd =
    -
    10999  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
    -
    11000  while(lastOffset < freeSpace1stTo2ndEnd)
    -
    11001  {
    -
    11002  // Find next non-null allocation or move nextAllocIndex to the end.
    -
    11003  while(nextAlloc1stIndex < suballoc1stCount &&
    -
    11004  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    -
    11005  {
    -
    11006  ++nextAlloc1stIndex;
    -
    11007  }
    -
    11008 
    -
    11009  // Found non-null allocation.
    -
    11010  if(nextAlloc1stIndex < suballoc1stCount)
    -
    11011  {
    -
    11012  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    -
    11013 
    -
    11014  // 1. Process free space before this allocation.
    -
    11015  if(lastOffset < suballoc.offset)
    -
    11016  {
    -
    11017  // There is free space from lastOffset to suballoc.offset.
    -
    11018  ++unusedRangeCount;
    -
    11019  }
    -
    11020 
    -
    11021  // 2. Process this allocation.
    -
    11022  // There is allocation with suballoc.offset, suballoc.size.
    -
    11023  ++alloc1stCount;
    -
    11024  usedBytes += suballoc.size;
    -
    11025 
    -
    11026  // 3. Prepare for next iteration.
    -
    11027  lastOffset = suballoc.offset + suballoc.size;
    -
    11028  ++nextAlloc1stIndex;
    -
    11029  }
    -
    11030  // We are at the end.
    -
    11031  else
    -
    11032  {
    -
    11033  if(lastOffset < size)
    -
    11034  {
    -
    11035  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    -
    11036  ++unusedRangeCount;
    -
    11037  }
    -
    11038 
    -
    11039  // End of loop.
    -
    11040  lastOffset = freeSpace1stTo2ndEnd;
    -
    11041  }
    -
    11042  }
    -
    11043 
    -
    11044  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    11045  {
    -
    11046  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    -
    11047  while(lastOffset < size)
    -
    11048  {
    -
    11049  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    -
    11050  while(nextAlloc2ndIndex != SIZE_MAX &&
    -
    11051  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    11052  {
    -
    11053  --nextAlloc2ndIndex;
    -
    11054  }
    -
    11055 
    -
    11056  // Found non-null allocation.
    -
    11057  if(nextAlloc2ndIndex != SIZE_MAX)
    -
    11058  {
    -
    11059  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    11060 
    -
    11061  // 1. Process free space before this allocation.
    -
    11062  if(lastOffset < suballoc.offset)
    -
    11063  {
    -
    11064  // There is free space from lastOffset to suballoc.offset.
    -
    11065  ++unusedRangeCount;
    -
    11066  }
    -
    11067 
    -
    11068  // 2. Process this allocation.
    -
    11069  // There is allocation with suballoc.offset, suballoc.size.
    -
    11070  ++alloc2ndCount;
    -
    11071  usedBytes += suballoc.size;
    -
    11072 
    -
    11073  // 3. Prepare for next iteration.
    -
    11074  lastOffset = suballoc.offset + suballoc.size;
    -
    11075  --nextAlloc2ndIndex;
    -
    11076  }
    -
    11077  // We are at the end.
    -
    11078  else
    -
    11079  {
    -
    11080  if(lastOffset < size)
    -
    11081  {
    -
    11082  // There is free space from lastOffset to size.
    -
    11083  ++unusedRangeCount;
    -
    11084  }
    -
    11085 
    -
    11086  // End of loop.
    -
    11087  lastOffset = size;
    -
    11088  }
    -
    11089  }
    -
    11090  }
    -
    11091 
    -
    11092  const VkDeviceSize unusedBytes = size - usedBytes;
    -
    11093  PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount);
    -
    11094 
    -
    11095  // SECOND PASS
    -
    11096  lastOffset = 0;
    -
    11097 
    -
    11098  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    11099  {
    -
    11100  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    -
    11101  size_t nextAlloc2ndIndex = 0;
    -
    11102  while(lastOffset < freeSpace2ndTo1stEnd)
    -
    11103  {
    -
    11104  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    -
    11105  while(nextAlloc2ndIndex < suballoc2ndCount &&
    -
    11106  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    11107  {
    -
    11108  ++nextAlloc2ndIndex;
    -
    11109  }
    -
    11110 
    -
    11111  // Found non-null allocation.
    -
    11112  if(nextAlloc2ndIndex < suballoc2ndCount)
    -
    11113  {
    -
    11114  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    11115 
    -
    11116  // 1. Process free space before this allocation.
    -
    11117  if(lastOffset < suballoc.offset)
    -
    11118  {
    -
    11119  // There is free space from lastOffset to suballoc.offset.
    -
    11120  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    11121  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    -
    11122  }
    -
    11123 
    -
    11124  // 2. Process this allocation.
    -
    11125  // There is allocation with suballoc.offset, suballoc.size.
    -
    11126  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    -
    11127 
    -
    11128  // 3. Prepare for next iteration.
    -
    11129  lastOffset = suballoc.offset + suballoc.size;
    -
    11130  ++nextAlloc2ndIndex;
    -
    11131  }
    -
    11132  // We are at the end.
    -
    11133  else
    -
    11134  {
    -
    11135  if(lastOffset < freeSpace2ndTo1stEnd)
    -
    11136  {
    -
    11137  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    -
    11138  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
    -
    11139  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    -
    11140  }
    -
    11141 
    -
    11142  // End of loop.
    -
    11143  lastOffset = freeSpace2ndTo1stEnd;
    -
    11144  }
    -
    11145  }
    -
    11146  }
    -
    11147 
    -
    11148  nextAlloc1stIndex = m_1stNullItemsBeginCount;
    -
    11149  while(lastOffset < freeSpace1stTo2ndEnd)
    -
    11150  {
    -
    11151  // Find next non-null allocation or move nextAllocIndex to the end.
    -
    11152  while(nextAlloc1stIndex < suballoc1stCount &&
    -
    11153  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    -
    11154  {
    -
    11155  ++nextAlloc1stIndex;
    -
    11156  }
    -
    11157 
    -
    11158  // Found non-null allocation.
    -
    11159  if(nextAlloc1stIndex < suballoc1stCount)
    -
    11160  {
    -
    11161  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    +
    10926  // We are at the end.
    +
    10927  else
    +
    10928  {
    +
    10929  if(lastOffset < size)
    +
    10930  {
    +
    10931  // There is free space from lastOffset to size.
    +
    10932  const VkDeviceSize unusedRangeSize = size - lastOffset;
    +
    10933  inoutStats.unusedSize += unusedRangeSize;
    +
    10934  ++inoutStats.unusedRangeCount;
    +
    10935  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
    +
    10936  }
    +
    10937 
    +
    10938  // End of loop.
    +
    10939  lastOffset = size;
    +
    10940  }
    +
    10941  }
    +
    10942  }
    +
    10943 }
    +
    10944 
    +
    10945 #if VMA_STATS_STRING_ENABLED
    +
    10946 void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
    +
    10947 {
    +
    10948  const VkDeviceSize size = GetSize();
    +
    10949  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    10950  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    10951  const size_t suballoc1stCount = suballocations1st.size();
    +
    10952  const size_t suballoc2ndCount = suballocations2nd.size();
    +
    10953 
    +
    10954  // FIRST PASS
    +
    10955 
    +
    10956  size_t unusedRangeCount = 0;
    +
    10957  VkDeviceSize usedBytes = 0;
    +
    10958 
    +
    10959  VkDeviceSize lastOffset = 0;
    +
    10960 
    +
    10961  size_t alloc2ndCount = 0;
    +
    10962  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    10963  {
    +
    10964  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    +
    10965  size_t nextAlloc2ndIndex = 0;
    +
    10966  while(lastOffset < freeSpace2ndTo1stEnd)
    +
    10967  {
    +
    10968  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    +
    10969  while(nextAlloc2ndIndex < suballoc2ndCount &&
    +
    10970  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    10971  {
    +
    10972  ++nextAlloc2ndIndex;
    +
    10973  }
    +
    10974 
    +
    10975  // Found non-null allocation.
    +
    10976  if(nextAlloc2ndIndex < suballoc2ndCount)
    +
    10977  {
    +
    10978  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    10979 
    +
    10980  // 1. Process free space before this allocation.
    +
    10981  if(lastOffset < suballoc.offset)
    +
    10982  {
    +
    10983  // There is free space from lastOffset to suballoc.offset.
    +
    10984  ++unusedRangeCount;
    +
    10985  }
    +
    10986 
    +
    10987  // 2. Process this allocation.
    +
    10988  // There is allocation with suballoc.offset, suballoc.size.
    +
    10989  ++alloc2ndCount;
    +
    10990  usedBytes += suballoc.size;
    +
    10991 
    +
    10992  // 3. Prepare for next iteration.
    +
    10993  lastOffset = suballoc.offset + suballoc.size;
    +
    10994  ++nextAlloc2ndIndex;
    +
    10995  }
    +
    10996  // We are at the end.
    +
    10997  else
    +
    10998  {
    +
    10999  if(lastOffset < freeSpace2ndTo1stEnd)
    +
    11000  {
    +
    11001  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    +
    11002  ++unusedRangeCount;
    +
    11003  }
    +
    11004 
    +
    11005  // End of loop.
    +
    11006  lastOffset = freeSpace2ndTo1stEnd;
    +
    11007  }
    +
    11008  }
    +
    11009  }
    +
    11010 
    +
    11011  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
    +
    11012  size_t alloc1stCount = 0;
    +
    11013  const VkDeviceSize freeSpace1stTo2ndEnd =
    +
    11014  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
    +
    11015  while(lastOffset < freeSpace1stTo2ndEnd)
    +
    11016  {
    +
    11017  // Find next non-null allocation or move nextAllocIndex to the end.
    +
    11018  while(nextAlloc1stIndex < suballoc1stCount &&
    +
    11019  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    +
    11020  {
    +
    11021  ++nextAlloc1stIndex;
    +
    11022  }
    +
    11023 
    +
    11024  // Found non-null allocation.
    +
    11025  if(nextAlloc1stIndex < suballoc1stCount)
    +
    11026  {
    +
    11027  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    +
    11028 
    +
    11029  // 1. Process free space before this allocation.
    +
    11030  if(lastOffset < suballoc.offset)
    +
    11031  {
    +
    11032  // There is free space from lastOffset to suballoc.offset.
    +
    11033  ++unusedRangeCount;
    +
    11034  }
    +
    11035 
    +
    11036  // 2. Process this allocation.
    +
    11037  // There is allocation with suballoc.offset, suballoc.size.
    +
    11038  ++alloc1stCount;
    +
    11039  usedBytes += suballoc.size;
    +
    11040 
    +
    11041  // 3. Prepare for next iteration.
    +
    11042  lastOffset = suballoc.offset + suballoc.size;
    +
    11043  ++nextAlloc1stIndex;
    +
    11044  }
    +
    11045  // We are at the end.
    +
    11046  else
    +
    11047  {
    +
    11048  if(lastOffset < size)
    +
    11049  {
    +
    11050  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    +
    11051  ++unusedRangeCount;
    +
    11052  }
    +
    11053 
    +
    11054  // End of loop.
    +
    11055  lastOffset = freeSpace1stTo2ndEnd;
    +
    11056  }
    +
    11057  }
    +
    11058 
    +
    11059  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    11060  {
    +
    11061  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    +
    11062  while(lastOffset < size)
    +
    11063  {
    +
    11064  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    +
    11065  while(nextAlloc2ndIndex != SIZE_MAX &&
    +
    11066  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    11067  {
    +
    11068  --nextAlloc2ndIndex;
    +
    11069  }
    +
    11070 
    +
    11071  // Found non-null allocation.
    +
    11072  if(nextAlloc2ndIndex != SIZE_MAX)
    +
    11073  {
    +
    11074  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    11075 
    +
    11076  // 1. Process free space before this allocation.
    +
    11077  if(lastOffset < suballoc.offset)
    +
    11078  {
    +
    11079  // There is free space from lastOffset to suballoc.offset.
    +
    11080  ++unusedRangeCount;
    +
    11081  }
    +
    11082 
    +
    11083  // 2. Process this allocation.
    +
    11084  // There is allocation with suballoc.offset, suballoc.size.
    +
    11085  ++alloc2ndCount;
    +
    11086  usedBytes += suballoc.size;
    +
    11087 
    +
    11088  // 3. Prepare for next iteration.
    +
    11089  lastOffset = suballoc.offset + suballoc.size;
    +
    11090  --nextAlloc2ndIndex;
    +
    11091  }
    +
    11092  // We are at the end.
    +
    11093  else
    +
    11094  {
    +
    11095  if(lastOffset < size)
    +
    11096  {
    +
    11097  // There is free space from lastOffset to size.
    +
    11098  ++unusedRangeCount;
    +
    11099  }
    +
    11100 
    +
    11101  // End of loop.
    +
    11102  lastOffset = size;
    +
    11103  }
    +
    11104  }
    +
    11105  }
    +
    11106 
    +
    11107  const VkDeviceSize unusedBytes = size - usedBytes;
    +
    11108  PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount);
    +
    11109 
    +
    11110  // SECOND PASS
    +
    11111  lastOffset = 0;
    +
    11112 
    +
    11113  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    11114  {
    +
    11115  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
    +
    11116  size_t nextAlloc2ndIndex = 0;
    +
    11117  while(lastOffset < freeSpace2ndTo1stEnd)
    +
    11118  {
    +
    11119  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    +
    11120  while(nextAlloc2ndIndex < suballoc2ndCount &&
    +
    11121  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    11122  {
    +
    11123  ++nextAlloc2ndIndex;
    +
    11124  }
    +
    11125 
    +
    11126  // Found non-null allocation.
    +
    11127  if(nextAlloc2ndIndex < suballoc2ndCount)
    +
    11128  {
    +
    11129  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    11130 
    +
    11131  // 1. Process free space before this allocation.
    +
    11132  if(lastOffset < suballoc.offset)
    +
    11133  {
    +
    11134  // There is free space from lastOffset to suballoc.offset.
    +
    11135  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    11136  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    +
    11137  }
    +
    11138 
    +
    11139  // 2. Process this allocation.
    +
    11140  // There is allocation with suballoc.offset, suballoc.size.
    +
    11141  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    +
    11142 
    +
    11143  // 3. Prepare for next iteration.
    +
    11144  lastOffset = suballoc.offset + suballoc.size;
    +
    11145  ++nextAlloc2ndIndex;
    +
    11146  }
    +
    11147  // We are at the end.
    +
    11148  else
    +
    11149  {
    +
    11150  if(lastOffset < freeSpace2ndTo1stEnd)
    +
    11151  {
    +
    11152  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
    +
    11153  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
    +
    11154  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    +
    11155  }
    +
    11156 
    +
    11157  // End of loop.
    +
    11158  lastOffset = freeSpace2ndTo1stEnd;
    +
    11159  }
    +
    11160  }
    +
    11161  }
    11162 
    -
    11163  // 1. Process free space before this allocation.
    -
    11164  if(lastOffset < suballoc.offset)
    -
    11165  {
    -
    11166  // There is free space from lastOffset to suballoc.offset.
    -
    11167  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    11168  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    -
    11169  }
    -
    11170 
    -
    11171  // 2. Process this allocation.
    -
    11172  // There is allocation with suballoc.offset, suballoc.size.
    -
    11173  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    -
    11174 
    -
    11175  // 3. Prepare for next iteration.
    -
    11176  lastOffset = suballoc.offset + suballoc.size;
    -
    11177  ++nextAlloc1stIndex;
    -
    11178  }
    -
    11179  // We are at the end.
    -
    11180  else
    -
    11181  {
    -
    11182  if(lastOffset < freeSpace1stTo2ndEnd)
    -
    11183  {
    -
    11184  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    -
    11185  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
    -
    11186  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    -
    11187  }
    -
    11188 
    -
    11189  // End of loop.
    -
    11190  lastOffset = freeSpace1stTo2ndEnd;
    -
    11191  }
    -
    11192  }
    -
    11193 
    -
    11194  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    11195  {
    -
    11196  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    -
    11197  while(lastOffset < size)
    -
    11198  {
    -
    11199  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    -
    11200  while(nextAlloc2ndIndex != SIZE_MAX &&
    -
    11201  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    -
    11202  {
    -
    11203  --nextAlloc2ndIndex;
    -
    11204  }
    -
    11205 
    -
    11206  // Found non-null allocation.
    -
    11207  if(nextAlloc2ndIndex != SIZE_MAX)
    -
    11208  {
    -
    11209  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    -
    11210 
    -
    11211  // 1. Process free space before this allocation.
    -
    11212  if(lastOffset < suballoc.offset)
    -
    11213  {
    -
    11214  // There is free space from lastOffset to suballoc.offset.
    -
    11215  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    -
    11216  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    -
    11217  }
    -
    11218 
    -
    11219  // 2. Process this allocation.
    -
    11220  // There is allocation with suballoc.offset, suballoc.size.
    -
    11221  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    -
    11222 
    -
    11223  // 3. Prepare for next iteration.
    -
    11224  lastOffset = suballoc.offset + suballoc.size;
    -
    11225  --nextAlloc2ndIndex;
    -
    11226  }
    -
    11227  // We are at the end.
    -
    11228  else
    -
    11229  {
    -
    11230  if(lastOffset < size)
    -
    11231  {
    -
    11232  // There is free space from lastOffset to size.
    -
    11233  const VkDeviceSize unusedRangeSize = size - lastOffset;
    -
    11234  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    -
    11235  }
    -
    11236 
    -
    11237  // End of loop.
    -
    11238  lastOffset = size;
    -
    11239  }
    -
    11240  }
    -
    11241  }
    -
    11242 
    -
    11243  PrintDetailedMap_End(json);
    -
    11244 }
    -
    11245 #endif // #if VMA_STATS_STRING_ENABLED
    -
    11246 
    -
    11247 bool VmaBlockMetadata_Linear::CreateAllocationRequest(
    -
    11248  uint32_t currentFrameIndex,
    -
    11249  uint32_t frameInUseCount,
    -
    11250  VkDeviceSize bufferImageGranularity,
    -
    11251  VkDeviceSize allocSize,
    -
    11252  VkDeviceSize allocAlignment,
    -
    11253  bool upperAddress,
    -
    11254  VmaSuballocationType allocType,
    -
    11255  bool canMakeOtherLost,
    -
    11256  uint32_t strategy,
    -
    11257  VmaAllocationRequest* pAllocationRequest)
    -
    11258 {
    -
    11259  VMA_ASSERT(allocSize > 0);
    -
    11260  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    -
    11261  VMA_ASSERT(pAllocationRequest != VMA_NULL);
    -
    11262  VMA_HEAVY_ASSERT(Validate());
    -
    11263  return upperAddress ?
    -
    11264  CreateAllocationRequest_UpperAddress(
    -
    11265  currentFrameIndex, frameInUseCount, bufferImageGranularity,
    -
    11266  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest) :
    -
    11267  CreateAllocationRequest_LowerAddress(
    -
    11268  currentFrameIndex, frameInUseCount, bufferImageGranularity,
    -
    11269  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest);
    -
    11270 }
    -
    11271 
    -
    11272 bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress(
    -
    11273  uint32_t currentFrameIndex,
    -
    11274  uint32_t frameInUseCount,
    -
    11275  VkDeviceSize bufferImageGranularity,
    -
    11276  VkDeviceSize allocSize,
    -
    11277  VkDeviceSize allocAlignment,
    -
    11278  VmaSuballocationType allocType,
    -
    11279  bool canMakeOtherLost,
    -
    11280  uint32_t strategy,
    -
    11281  VmaAllocationRequest* pAllocationRequest)
    -
    11282 {
    -
    11283  const VkDeviceSize size = GetSize();
    -
    11284  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11285  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11163  nextAlloc1stIndex = m_1stNullItemsBeginCount;
    +
    11164  while(lastOffset < freeSpace1stTo2ndEnd)
    +
    11165  {
    +
    11166  // Find next non-null allocation or move nextAllocIndex to the end.
    +
    11167  while(nextAlloc1stIndex < suballoc1stCount &&
    +
    11168  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
    +
    11169  {
    +
    11170  ++nextAlloc1stIndex;
    +
    11171  }
    +
    11172 
    +
    11173  // Found non-null allocation.
    +
    11174  if(nextAlloc1stIndex < suballoc1stCount)
    +
    11175  {
    +
    11176  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
    +
    11177 
    +
    11178  // 1. Process free space before this allocation.
    +
    11179  if(lastOffset < suballoc.offset)
    +
    11180  {
    +
    11181  // There is free space from lastOffset to suballoc.offset.
    +
    11182  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    11183  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    +
    11184  }
    +
    11185 
    +
    11186  // 2. Process this allocation.
    +
    11187  // There is allocation with suballoc.offset, suballoc.size.
    +
    11188  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    +
    11189 
    +
    11190  // 3. Prepare for next iteration.
    +
    11191  lastOffset = suballoc.offset + suballoc.size;
    +
    11192  ++nextAlloc1stIndex;
    +
    11193  }
    +
    11194  // We are at the end.
    +
    11195  else
    +
    11196  {
    +
    11197  if(lastOffset < freeSpace1stTo2ndEnd)
    +
    11198  {
    +
    11199  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
    +
    11200  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
    +
    11201  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    +
    11202  }
    +
    11203 
    +
    11204  // End of loop.
    +
    11205  lastOffset = freeSpace1stTo2ndEnd;
    +
    11206  }
    +
    11207  }
    +
    11208 
    +
    11209  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    11210  {
    +
    11211  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
    +
    11212  while(lastOffset < size)
    +
    11213  {
    +
    11214  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
    +
    11215  while(nextAlloc2ndIndex != SIZE_MAX &&
    +
    11216  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
    +
    11217  {
    +
    11218  --nextAlloc2ndIndex;
    +
    11219  }
    +
    11220 
    +
    11221  // Found non-null allocation.
    +
    11222  if(nextAlloc2ndIndex != SIZE_MAX)
    +
    11223  {
    +
    11224  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
    +
    11225 
    +
    11226  // 1. Process free space before this allocation.
    +
    11227  if(lastOffset < suballoc.offset)
    +
    11228  {
    +
    11229  // There is free space from lastOffset to suballoc.offset.
    +
    11230  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
    +
    11231  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    +
    11232  }
    +
    11233 
    +
    11234  // 2. Process this allocation.
    +
    11235  // There is allocation with suballoc.offset, suballoc.size.
    +
    11236  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
    +
    11237 
    +
    11238  // 3. Prepare for next iteration.
    +
    11239  lastOffset = suballoc.offset + suballoc.size;
    +
    11240  --nextAlloc2ndIndex;
    +
    11241  }
    +
    11242  // We are at the end.
    +
    11243  else
    +
    11244  {
    +
    11245  if(lastOffset < size)
    +
    11246  {
    +
    11247  // There is free space from lastOffset to size.
    +
    11248  const VkDeviceSize unusedRangeSize = size - lastOffset;
    +
    11249  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
    +
    11250  }
    +
    11251 
    +
    11252  // End of loop.
    +
    11253  lastOffset = size;
    +
    11254  }
    +
    11255  }
    +
    11256  }
    +
    11257 
    +
    11258  PrintDetailedMap_End(json);
    +
    11259 }
    +
    11260 #endif // #if VMA_STATS_STRING_ENABLED
    +
    11261 
    +
    11262 bool VmaBlockMetadata_Linear::CreateAllocationRequest(
    +
    11263  uint32_t currentFrameIndex,
    +
    11264  uint32_t frameInUseCount,
    +
    11265  VkDeviceSize bufferImageGranularity,
    +
    11266  VkDeviceSize allocSize,
    +
    11267  VkDeviceSize allocAlignment,
    +
    11268  bool upperAddress,
    +
    11269  VmaSuballocationType allocType,
    +
    11270  bool canMakeOtherLost,
    +
    11271  uint32_t strategy,
    +
    11272  VmaAllocationRequest* pAllocationRequest)
    +
    11273 {
    +
    11274  VMA_ASSERT(allocSize > 0);
    +
    11275  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    +
    11276  VMA_ASSERT(pAllocationRequest != VMA_NULL);
    +
    11277  VMA_HEAVY_ASSERT(Validate());
    +
    11278  return upperAddress ?
    +
    11279  CreateAllocationRequest_UpperAddress(
    +
    11280  currentFrameIndex, frameInUseCount, bufferImageGranularity,
    +
    11281  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest) :
    +
    11282  CreateAllocationRequest_LowerAddress(
    +
    11283  currentFrameIndex, frameInUseCount, bufferImageGranularity,
    +
    11284  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest);
    +
    11285 }
    11286 
    -
    11287  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    11288  {
    -
    11289  VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer.");
    -
    11290  return false;
    -
    11291  }
    -
    11292 
    -
    11293  // Try to allocate before 2nd.back(), or end of block if 2nd.empty().
    -
    11294  if(allocSize > size)
    -
    11295  {
    -
    11296  return false;
    -
    11297  }
    -
    11298  VkDeviceSize resultBaseOffset = size - allocSize;
    -
    11299  if(!suballocations2nd.empty())
    -
    11300  {
    -
    11301  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
    -
    11302  resultBaseOffset = lastSuballoc.offset - allocSize;
    -
    11303  if(allocSize > lastSuballoc.offset)
    -
    11304  {
    -
    11305  return false;
    -
    11306  }
    -
    11307  }
    -
    11308 
    -
    11309  // Start from offset equal to end of free space.
    -
    11310  VkDeviceSize resultOffset = resultBaseOffset;
    -
    11311 
    -
    11312  // Apply VMA_DEBUG_MARGIN at the end.
    -
    11313  if(VMA_DEBUG_MARGIN > 0)
    -
    11314  {
    -
    11315  if(resultOffset < VMA_DEBUG_MARGIN)
    -
    11316  {
    -
    11317  return false;
    -
    11318  }
    -
    11319  resultOffset -= VMA_DEBUG_MARGIN;
    -
    11320  }
    -
    11321 
    -
    11322  // Apply alignment.
    -
    11323  resultOffset = VmaAlignDown(resultOffset, allocAlignment);
    -
    11324 
    -
    11325  // Check next suballocations from 2nd for BufferImageGranularity conflicts.
    -
    11326  // Make bigger alignment if necessary.
    -
    11327  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
    -
    11328  {
    -
    11329  bool bufferImageGranularityConflict = false;
    -
    11330  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
    +
    11287 bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress(
    +
    11288  uint32_t currentFrameIndex,
    +
    11289  uint32_t frameInUseCount,
    +
    11290  VkDeviceSize bufferImageGranularity,
    +
    11291  VkDeviceSize allocSize,
    +
    11292  VkDeviceSize allocAlignment,
    +
    11293  VmaSuballocationType allocType,
    +
    11294  bool canMakeOtherLost,
    +
    11295  uint32_t strategy,
    +
    11296  VmaAllocationRequest* pAllocationRequest)
    +
    11297 {
    +
    11298  const VkDeviceSize size = GetSize();
    +
    11299  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11300  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11301 
    +
    11302  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    11303  {
    +
    11304  VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer.");
    +
    11305  return false;
    +
    11306  }
    +
    11307 
    +
    11308  // Try to allocate before 2nd.back(), or end of block if 2nd.empty().
    +
    11309  if(allocSize > size)
    +
    11310  {
    +
    11311  return false;
    +
    11312  }
    +
    11313  VkDeviceSize resultBaseOffset = size - allocSize;
    +
    11314  if(!suballocations2nd.empty())
    +
    11315  {
    +
    11316  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
    +
    11317  resultBaseOffset = lastSuballoc.offset - allocSize;
    +
    11318  if(allocSize > lastSuballoc.offset)
    +
    11319  {
    +
    11320  return false;
    +
    11321  }
    +
    11322  }
    +
    11323 
    +
    11324  // Start from offset equal to end of free space.
    +
    11325  VkDeviceSize resultOffset = resultBaseOffset;
    +
    11326 
    +
    11327  // Apply VMA_DEBUG_MARGIN at the end.
    +
    11328  if(VMA_DEBUG_MARGIN > 0)
    +
    11329  {
    +
    11330  if(resultOffset < VMA_DEBUG_MARGIN)
    11331  {
    -
    11332  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
    -
    11333  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    -
    11334  {
    -
    11335  if(VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType))
    -
    11336  {
    -
    11337  bufferImageGranularityConflict = true;
    -
    11338  break;
    -
    11339  }
    -
    11340  }
    -
    11341  else
    -
    11342  // Already on previous page.
    -
    11343  break;
    -
    11344  }
    -
    11345  if(bufferImageGranularityConflict)
    +
    11332  return false;
    +
    11333  }
    +
    11334  resultOffset -= VMA_DEBUG_MARGIN;
    +
    11335  }
    +
    11336 
    +
    11337  // Apply alignment.
    +
    11338  resultOffset = VmaAlignDown(resultOffset, allocAlignment);
    +
    11339 
    +
    11340  // Check next suballocations from 2nd for BufferImageGranularity conflicts.
    +
    11341  // Make bigger alignment if necessary.
    +
    11342  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
    +
    11343  {
    +
    11344  bool bufferImageGranularityConflict = false;
    +
    11345  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
    11346  {
    -
    11347  resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity);
    -
    11348  }
    -
    11349  }
    -
    11350 
    -
    11351  // There is enough free space.
    -
    11352  const VkDeviceSize endOf1st = !suballocations1st.empty() ?
    -
    11353  suballocations1st.back().offset + suballocations1st.back().size :
    -
    11354  0;
    -
    11355  if(endOf1st + VMA_DEBUG_MARGIN <= resultOffset)
    -
    11356  {
    -
    11357  // Check previous suballocations for BufferImageGranularity conflicts.
    -
    11358  // If conflict exists, allocation cannot be made here.
    -
    11359  if(bufferImageGranularity > 1)
    -
    11360  {
    -
    11361  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
    -
    11362  {
    -
    11363  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
    -
    11364  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
    -
    11365  {
    -
    11366  if(VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type))
    -
    11367  {
    -
    11368  return false;
    -
    11369  }
    -
    11370  }
    -
    11371  else
    -
    11372  {
    -
    11373  // Already on next page.
    -
    11374  break;
    -
    11375  }
    -
    11376  }
    -
    11377  }
    -
    11378 
    -
    11379  // All tests passed: Success.
    -
    11380  pAllocationRequest->offset = resultOffset;
    -
    11381  pAllocationRequest->sumFreeSize = resultBaseOffset + allocSize - endOf1st;
    -
    11382  pAllocationRequest->sumItemSize = 0;
    -
    11383  // pAllocationRequest->item unused.
    -
    11384  pAllocationRequest->itemsToMakeLostCount = 0;
    -
    11385  pAllocationRequest->type = VmaAllocationRequestType::UpperAddress;
    -
    11386  return true;
    -
    11387  }
    -
    11388 
    -
    11389  return false;
    -
    11390 }
    -
    11391 
    -
    11392 bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress(
    -
    11393  uint32_t currentFrameIndex,
    -
    11394  uint32_t frameInUseCount,
    -
    11395  VkDeviceSize bufferImageGranularity,
    -
    11396  VkDeviceSize allocSize,
    -
    11397  VkDeviceSize allocAlignment,
    -
    11398  VmaSuballocationType allocType,
    -
    11399  bool canMakeOtherLost,
    -
    11400  uint32_t strategy,
    -
    11401  VmaAllocationRequest* pAllocationRequest)
    -
    11402 {
    -
    11403  const VkDeviceSize size = GetSize();
    -
    11404  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11405  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11347  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
    +
    11348  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    +
    11349  {
    +
    11350  if(VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType))
    +
    11351  {
    +
    11352  bufferImageGranularityConflict = true;
    +
    11353  break;
    +
    11354  }
    +
    11355  }
    +
    11356  else
    +
    11357  // Already on previous page.
    +
    11358  break;
    +
    11359  }
    +
    11360  if(bufferImageGranularityConflict)
    +
    11361  {
    +
    11362  resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity);
    +
    11363  }
    +
    11364  }
    +
    11365 
    +
    11366  // There is enough free space.
    +
    11367  const VkDeviceSize endOf1st = !suballocations1st.empty() ?
    +
    11368  suballocations1st.back().offset + suballocations1st.back().size :
    +
    11369  0;
    +
    11370  if(endOf1st + VMA_DEBUG_MARGIN <= resultOffset)
    +
    11371  {
    +
    11372  // Check previous suballocations for BufferImageGranularity conflicts.
    +
    11373  // If conflict exists, allocation cannot be made here.
    +
    11374  if(bufferImageGranularity > 1)
    +
    11375  {
    +
    11376  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
    +
    11377  {
    +
    11378  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
    +
    11379  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
    +
    11380  {
    +
    11381  if(VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type))
    +
    11382  {
    +
    11383  return false;
    +
    11384  }
    +
    11385  }
    +
    11386  else
    +
    11387  {
    +
    11388  // Already on next page.
    +
    11389  break;
    +
    11390  }
    +
    11391  }
    +
    11392  }
    +
    11393 
    +
    11394  // All tests passed: Success.
    +
    11395  pAllocationRequest->offset = resultOffset;
    +
    11396  pAllocationRequest->sumFreeSize = resultBaseOffset + allocSize - endOf1st;
    +
    11397  pAllocationRequest->sumItemSize = 0;
    +
    11398  // pAllocationRequest->item unused.
    +
    11399  pAllocationRequest->itemsToMakeLostCount = 0;
    +
    11400  pAllocationRequest->type = VmaAllocationRequestType::UpperAddress;
    +
    11401  return true;
    +
    11402  }
    +
    11403 
    +
    11404  return false;
    +
    11405 }
    11406 
    -
    11407  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    11408  {
    -
    11409  // Try to allocate at the end of 1st vector.
    -
    11410 
    -
    11411  VkDeviceSize resultBaseOffset = 0;
    -
    11412  if(!suballocations1st.empty())
    -
    11413  {
    -
    11414  const VmaSuballocation& lastSuballoc = suballocations1st.back();
    -
    11415  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
    -
    11416  }
    -
    11417 
    -
    11418  // Start from offset equal to beginning of free space.
    -
    11419  VkDeviceSize resultOffset = resultBaseOffset;
    -
    11420 
    -
    11421  // Apply VMA_DEBUG_MARGIN at the beginning.
    -
    11422  if(VMA_DEBUG_MARGIN > 0)
    -
    11423  {
    -
    11424  resultOffset += VMA_DEBUG_MARGIN;
    -
    11425  }
    -
    11426 
    -
    11427  // Apply alignment.
    -
    11428  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
    -
    11429 
    -
    11430  // Check previous suballocations for BufferImageGranularity conflicts.
    -
    11431  // Make bigger alignment if necessary.
    -
    11432  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations1st.empty())
    -
    11433  {
    -
    11434  bool bufferImageGranularityConflict = false;
    -
    11435  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
    -
    11436  {
    -
    11437  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
    -
    11438  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
    -
    11439  {
    -
    11440  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    -
    11441  {
    -
    11442  bufferImageGranularityConflict = true;
    -
    11443  break;
    -
    11444  }
    -
    11445  }
    -
    11446  else
    -
    11447  // Already on previous page.
    -
    11448  break;
    -
    11449  }
    -
    11450  if(bufferImageGranularityConflict)
    +
    11407 bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress(
    +
    11408  uint32_t currentFrameIndex,
    +
    11409  uint32_t frameInUseCount,
    +
    11410  VkDeviceSize bufferImageGranularity,
    +
    11411  VkDeviceSize allocSize,
    +
    11412  VkDeviceSize allocAlignment,
    +
    11413  VmaSuballocationType allocType,
    +
    11414  bool canMakeOtherLost,
    +
    11415  uint32_t strategy,
    +
    11416  VmaAllocationRequest* pAllocationRequest)
    +
    11417 {
    +
    11418  const VkDeviceSize size = GetSize();
    +
    11419  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11420  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11421 
    +
    11422  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    11423  {
    +
    11424  // Try to allocate at the end of 1st vector.
    +
    11425 
    +
    11426  VkDeviceSize resultBaseOffset = 0;
    +
    11427  if(!suballocations1st.empty())
    +
    11428  {
    +
    11429  const VmaSuballocation& lastSuballoc = suballocations1st.back();
    +
    11430  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
    +
    11431  }
    +
    11432 
    +
    11433  // Start from offset equal to beginning of free space.
    +
    11434  VkDeviceSize resultOffset = resultBaseOffset;
    +
    11435 
    +
    11436  // Apply VMA_DEBUG_MARGIN at the beginning.
    +
    11437  if(VMA_DEBUG_MARGIN > 0)
    +
    11438  {
    +
    11439  resultOffset += VMA_DEBUG_MARGIN;
    +
    11440  }
    +
    11441 
    +
    11442  // Apply alignment.
    +
    11443  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
    +
    11444 
    +
    11445  // Check previous suballocations for BufferImageGranularity conflicts.
    +
    11446  // Make bigger alignment if necessary.
    +
    11447  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations1st.empty())
    +
    11448  {
    +
    11449  bool bufferImageGranularityConflict = false;
    +
    11450  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
    11451  {
    -
    11452  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
    -
    11453  }
    -
    11454  }
    -
    11455 
    -
    11456  const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
    -
    11457  suballocations2nd.back().offset : size;
    -
    11458 
    -
    11459  // There is enough free space at the end after alignment.
    -
    11460  if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd)
    -
    11461  {
    -
    11462  // Check next suballocations for BufferImageGranularity conflicts.
    -
    11463  // If conflict exists, allocation cannot be made here.
    -
    11464  if((allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    11465  {
    -
    11466  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
    -
    11467  {
    -
    11468  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
    -
    11469  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    -
    11470  {
    -
    11471  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    -
    11472  {
    -
    11473  return false;
    -
    11474  }
    -
    11475  }
    -
    11476  else
    -
    11477  {
    -
    11478  // Already on previous page.
    -
    11479  break;
    -
    11480  }
    -
    11481  }
    -
    11482  }
    -
    11483 
    -
    11484  // All tests passed: Success.
    -
    11485  pAllocationRequest->offset = resultOffset;
    -
    11486  pAllocationRequest->sumFreeSize = freeSpaceEnd - resultBaseOffset;
    -
    11487  pAllocationRequest->sumItemSize = 0;
    -
    11488  // pAllocationRequest->item, customData unused.
    -
    11489  pAllocationRequest->type = VmaAllocationRequestType::EndOf1st;
    -
    11490  pAllocationRequest->itemsToMakeLostCount = 0;
    -
    11491  return true;
    -
    11492  }
    -
    11493  }
    -
    11494 
    -
    11495  // Wrap-around to end of 2nd vector. Try to allocate there, watching for the
    -
    11496  // beginning of 1st vector as the end of free space.
    -
    11497  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    11498  {
    -
    11499  VMA_ASSERT(!suballocations1st.empty());
    -
    11500 
    -
    11501  VkDeviceSize resultBaseOffset = 0;
    -
    11502  if(!suballocations2nd.empty())
    -
    11503  {
    -
    11504  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
    -
    11505  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
    -
    11506  }
    -
    11507 
    -
    11508  // Start from offset equal to beginning of free space.
    -
    11509  VkDeviceSize resultOffset = resultBaseOffset;
    -
    11510 
    -
    11511  // Apply VMA_DEBUG_MARGIN at the beginning.
    -
    11512  if(VMA_DEBUG_MARGIN > 0)
    -
    11513  {
    -
    11514  resultOffset += VMA_DEBUG_MARGIN;
    -
    11515  }
    -
    11516 
    -
    11517  // Apply alignment.
    -
    11518  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
    -
    11519 
    -
    11520  // Check previous suballocations for BufferImageGranularity conflicts.
    -
    11521  // Make bigger alignment if necessary.
    -
    11522  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
    -
    11523  {
    -
    11524  bool bufferImageGranularityConflict = false;
    -
    11525  for(size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; )
    -
    11526  {
    -
    11527  const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex];
    -
    11528  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
    -
    11529  {
    -
    11530  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    -
    11531  {
    -
    11532  bufferImageGranularityConflict = true;
    -
    11533  break;
    -
    11534  }
    -
    11535  }
    -
    11536  else
    -
    11537  // Already on previous page.
    -
    11538  break;
    -
    11539  }
    -
    11540  if(bufferImageGranularityConflict)
    +
    11452  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
    +
    11453  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
    +
    11454  {
    +
    11455  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    +
    11456  {
    +
    11457  bufferImageGranularityConflict = true;
    +
    11458  break;
    +
    11459  }
    +
    11460  }
    +
    11461  else
    +
    11462  // Already on previous page.
    +
    11463  break;
    +
    11464  }
    +
    11465  if(bufferImageGranularityConflict)
    +
    11466  {
    +
    11467  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
    +
    11468  }
    +
    11469  }
    +
    11470 
    +
    11471  const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
    +
    11472  suballocations2nd.back().offset : size;
    +
    11473 
    +
    11474  // There is enough free space at the end after alignment.
    +
    11475  if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd)
    +
    11476  {
    +
    11477  // Check next suballocations for BufferImageGranularity conflicts.
    +
    11478  // If conflict exists, allocation cannot be made here.
    +
    11479  if((allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    11480  {
    +
    11481  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
    +
    11482  {
    +
    11483  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
    +
    11484  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    +
    11485  {
    +
    11486  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    +
    11487  {
    +
    11488  return false;
    +
    11489  }
    +
    11490  }
    +
    11491  else
    +
    11492  {
    +
    11493  // Already on previous page.
    +
    11494  break;
    +
    11495  }
    +
    11496  }
    +
    11497  }
    +
    11498 
    +
    11499  // All tests passed: Success.
    +
    11500  pAllocationRequest->offset = resultOffset;
    +
    11501  pAllocationRequest->sumFreeSize = freeSpaceEnd - resultBaseOffset;
    +
    11502  pAllocationRequest->sumItemSize = 0;
    +
    11503  // pAllocationRequest->item, customData unused.
    +
    11504  pAllocationRequest->type = VmaAllocationRequestType::EndOf1st;
    +
    11505  pAllocationRequest->itemsToMakeLostCount = 0;
    +
    11506  return true;
    +
    11507  }
    +
    11508  }
    +
    11509 
    +
    11510  // Wrap-around to end of 2nd vector. Try to allocate there, watching for the
    +
    11511  // beginning of 1st vector as the end of free space.
    +
    11512  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    11513  {
    +
    11514  VMA_ASSERT(!suballocations1st.empty());
    +
    11515 
    +
    11516  VkDeviceSize resultBaseOffset = 0;
    +
    11517  if(!suballocations2nd.empty())
    +
    11518  {
    +
    11519  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
    +
    11520  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
    +
    11521  }
    +
    11522 
    +
    11523  // Start from offset equal to beginning of free space.
    +
    11524  VkDeviceSize resultOffset = resultBaseOffset;
    +
    11525 
    +
    11526  // Apply VMA_DEBUG_MARGIN at the beginning.
    +
    11527  if(VMA_DEBUG_MARGIN > 0)
    +
    11528  {
    +
    11529  resultOffset += VMA_DEBUG_MARGIN;
    +
    11530  }
    +
    11531 
    +
    11532  // Apply alignment.
    +
    11533  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
    +
    11534 
    +
    11535  // Check previous suballocations for BufferImageGranularity conflicts.
    +
    11536  // Make bigger alignment if necessary.
    +
    11537  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
    +
    11538  {
    +
    11539  bool bufferImageGranularityConflict = false;
    +
    11540  for(size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; )
    11541  {
    -
    11542  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
    -
    11543  }
    -
    11544  }
    -
    11545 
    -
    11546  pAllocationRequest->itemsToMakeLostCount = 0;
    -
    11547  pAllocationRequest->sumItemSize = 0;
    -
    11548  size_t index1st = m_1stNullItemsBeginCount;
    -
    11549 
    -
    11550  if(canMakeOtherLost)
    -
    11551  {
    -
    11552  while(index1st < suballocations1st.size() &&
    -
    11553  resultOffset + allocSize + VMA_DEBUG_MARGIN > suballocations1st[index1st].offset)
    -
    11554  {
    -
    11555  // Next colliding allocation at the beginning of 1st vector found. Try to make it lost.
    -
    11556  const VmaSuballocation& suballoc = suballocations1st[index1st];
    -
    11557  if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    11558  {
    -
    11559  // No problem.
    -
    11560  }
    -
    11561  else
    -
    11562  {
    -
    11563  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
    -
    11564  if(suballoc.hAllocation->CanBecomeLost() &&
    -
    11565  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    -
    11566  {
    -
    11567  ++pAllocationRequest->itemsToMakeLostCount;
    -
    11568  pAllocationRequest->sumItemSize += suballoc.size;
    -
    11569  }
    -
    11570  else
    -
    11571  {
    -
    11572  return false;
    -
    11573  }
    -
    11574  }
    -
    11575  ++index1st;
    -
    11576  }
    -
    11577 
    -
    11578  // Check next suballocations for BufferImageGranularity conflicts.
    -
    11579  // If conflict exists, we must mark more allocations lost or fail.
    -
    11580  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
    -
    11581  {
    -
    11582  while(index1st < suballocations1st.size())
    -
    11583  {
    -
    11584  const VmaSuballocation& suballoc = suballocations1st[index1st];
    -
    11585  if(VmaBlocksOnSamePage(resultOffset, allocSize, suballoc.offset, bufferImageGranularity))
    +
    11542  const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex];
    +
    11543  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
    +
    11544  {
    +
    11545  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    +
    11546  {
    +
    11547  bufferImageGranularityConflict = true;
    +
    11548  break;
    +
    11549  }
    +
    11550  }
    +
    11551  else
    +
    11552  // Already on previous page.
    +
    11553  break;
    +
    11554  }
    +
    11555  if(bufferImageGranularityConflict)
    +
    11556  {
    +
    11557  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
    +
    11558  }
    +
    11559  }
    +
    11560 
    +
    11561  pAllocationRequest->itemsToMakeLostCount = 0;
    +
    11562  pAllocationRequest->sumItemSize = 0;
    +
    11563  size_t index1st = m_1stNullItemsBeginCount;
    +
    11564 
    +
    11565  if(canMakeOtherLost)
    +
    11566  {
    +
    11567  while(index1st < suballocations1st.size() &&
    +
    11568  resultOffset + allocSize + VMA_DEBUG_MARGIN > suballocations1st[index1st].offset)
    +
    11569  {
    +
    11570  // Next colliding allocation at the beginning of 1st vector found. Try to make it lost.
    +
    11571  const VmaSuballocation& suballoc = suballocations1st[index1st];
    +
    11572  if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    11573  {
    +
    11574  // No problem.
    +
    11575  }
    +
    11576  else
    +
    11577  {
    +
    11578  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
    +
    11579  if(suballoc.hAllocation->CanBecomeLost() &&
    +
    11580  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    +
    11581  {
    +
    11582  ++pAllocationRequest->itemsToMakeLostCount;
    +
    11583  pAllocationRequest->sumItemSize += suballoc.size;
    +
    11584  }
    +
    11585  else
    11586  {
    -
    11587  if(suballoc.hAllocation != VK_NULL_HANDLE)
    -
    11588  {
    -
    11589  // Not checking actual VmaIsBufferImageGranularityConflict(allocType, suballoc.type).
    -
    11590  if(suballoc.hAllocation->CanBecomeLost() &&
    -
    11591  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    -
    11592  {
    -
    11593  ++pAllocationRequest->itemsToMakeLostCount;
    -
    11594  pAllocationRequest->sumItemSize += suballoc.size;
    -
    11595  }
    -
    11596  else
    -
    11597  {
    -
    11598  return false;
    -
    11599  }
    -
    11600  }
    -
    11601  }
    -
    11602  else
    -
    11603  {
    -
    11604  // Already on next page.
    -
    11605  break;
    -
    11606  }
    -
    11607  ++index1st;
    -
    11608  }
    -
    11609  }
    -
    11610 
    -
    11611  // Special case: There is not enough room at the end for this allocation, even after making all from the 1st lost.
    -
    11612  if(index1st == suballocations1st.size() &&
    -
    11613  resultOffset + allocSize + VMA_DEBUG_MARGIN > size)
    -
    11614  {
    -
    11615  // TODO: This is a known bug that it's not yet implemented and the allocation is failing.
    -
    11616  VMA_DEBUG_LOG("Unsupported special case in custom pool with linear allocation algorithm used as ring buffer with allocations that can be lost.");
    -
    11617  }
    -
    11618  }
    -
    11619 
    -
    11620  // There is enough free space at the end after alignment.
    -
    11621  if((index1st == suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= size) ||
    -
    11622  (index1st < suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= suballocations1st[index1st].offset))
    -
    11623  {
    -
    11624  // Check next suballocations for BufferImageGranularity conflicts.
    -
    11625  // If conflict exists, allocation cannot be made here.
    -
    11626  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
    -
    11627  {
    -
    11628  for(size_t nextSuballocIndex = index1st;
    -
    11629  nextSuballocIndex < suballocations1st.size();
    -
    11630  nextSuballocIndex++)
    -
    11631  {
    -
    11632  const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex];
    -
    11633  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    -
    11634  {
    -
    11635  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    -
    11636  {
    -
    11637  return false;
    -
    11638  }
    -
    11639  }
    -
    11640  else
    -
    11641  {
    -
    11642  // Already on next page.
    -
    11643  break;
    -
    11644  }
    -
    11645  }
    -
    11646  }
    -
    11647 
    -
    11648  // All tests passed: Success.
    -
    11649  pAllocationRequest->offset = resultOffset;
    -
    11650  pAllocationRequest->sumFreeSize =
    -
    11651  (index1st < suballocations1st.size() ? suballocations1st[index1st].offset : size)
    -
    11652  - resultBaseOffset
    -
    11653  - pAllocationRequest->sumItemSize;
    -
    11654  pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd;
    -
    11655  // pAllocationRequest->item, customData unused.
    -
    11656  return true;
    -
    11657  }
    -
    11658  }
    -
    11659 
    -
    11660  return false;
    -
    11661 }
    +
    11587  return false;
    +
    11588  }
    +
    11589  }
    +
    11590  ++index1st;
    +
    11591  }
    +
    11592 
    +
    11593  // Check next suballocations for BufferImageGranularity conflicts.
    +
    11594  // If conflict exists, we must mark more allocations lost or fail.
    +
    11595  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
    +
    11596  {
    +
    11597  while(index1st < suballocations1st.size())
    +
    11598  {
    +
    11599  const VmaSuballocation& suballoc = suballocations1st[index1st];
    +
    11600  if(VmaBlocksOnSamePage(resultOffset, allocSize, suballoc.offset, bufferImageGranularity))
    +
    11601  {
    +
    11602  if(suballoc.hAllocation != VK_NULL_HANDLE)
    +
    11603  {
    +
    11604  // Not checking actual VmaIsBufferImageGranularityConflict(allocType, suballoc.type).
    +
    11605  if(suballoc.hAllocation->CanBecomeLost() &&
    +
    11606  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
    +
    11607  {
    +
    11608  ++pAllocationRequest->itemsToMakeLostCount;
    +
    11609  pAllocationRequest->sumItemSize += suballoc.size;
    +
    11610  }
    +
    11611  else
    +
    11612  {
    +
    11613  return false;
    +
    11614  }
    +
    11615  }
    +
    11616  }
    +
    11617  else
    +
    11618  {
    +
    11619  // Already on next page.
    +
    11620  break;
    +
    11621  }
    +
    11622  ++index1st;
    +
    11623  }
    +
    11624  }
    +
    11625 
    +
    11626  // Special case: There is not enough room at the end for this allocation, even after making all from the 1st lost.
    +
    11627  if(index1st == suballocations1st.size() &&
    +
    11628  resultOffset + allocSize + VMA_DEBUG_MARGIN > size)
    +
    11629  {
    +
    11630  // TODO: This is a known bug that it's not yet implemented and the allocation is failing.
    +
    11631  VMA_DEBUG_LOG("Unsupported special case in custom pool with linear allocation algorithm used as ring buffer with allocations that can be lost.");
    +
    11632  }
    +
    11633  }
    +
    11634 
    +
    11635  // There is enough free space at the end after alignment.
    +
    11636  if((index1st == suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= size) ||
    +
    11637  (index1st < suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= suballocations1st[index1st].offset))
    +
    11638  {
    +
    11639  // Check next suballocations for BufferImageGranularity conflicts.
    +
    11640  // If conflict exists, allocation cannot be made here.
    +
    11641  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
    +
    11642  {
    +
    11643  for(size_t nextSuballocIndex = index1st;
    +
    11644  nextSuballocIndex < suballocations1st.size();
    +
    11645  nextSuballocIndex++)
    +
    11646  {
    +
    11647  const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex];
    +
    11648  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    +
    11649  {
    +
    11650  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    +
    11651  {
    +
    11652  return false;
    +
    11653  }
    +
    11654  }
    +
    11655  else
    +
    11656  {
    +
    11657  // Already on next page.
    +
    11658  break;
    +
    11659  }
    +
    11660  }
    +
    11661  }
    11662 
    -
    11663 bool VmaBlockMetadata_Linear::MakeRequestedAllocationsLost(
    -
    11664  uint32_t currentFrameIndex,
    -
    11665  uint32_t frameInUseCount,
    -
    11666  VmaAllocationRequest* pAllocationRequest)
    -
    11667 {
    -
    11668  if(pAllocationRequest->itemsToMakeLostCount == 0)
    -
    11669  {
    -
    11670  return true;
    -
    11671  }
    -
    11672 
    -
    11673  VMA_ASSERT(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER);
    +
    11663  // All tests passed: Success.
    +
    11664  pAllocationRequest->offset = resultOffset;
    +
    11665  pAllocationRequest->sumFreeSize =
    +
    11666  (index1st < suballocations1st.size() ? suballocations1st[index1st].offset : size)
    +
    11667  - resultBaseOffset
    +
    11668  - pAllocationRequest->sumItemSize;
    +
    11669  pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd;
    +
    11670  // pAllocationRequest->item, customData unused.
    +
    11671  return true;
    +
    11672  }
    +
    11673  }
    11674 
    -
    11675  // We always start from 1st.
    -
    11676  SuballocationVectorType* suballocations = &AccessSuballocations1st();
    -
    11677  size_t index = m_1stNullItemsBeginCount;
    -
    11678  size_t madeLostCount = 0;
    -
    11679  while(madeLostCount < pAllocationRequest->itemsToMakeLostCount)
    -
    11680  {
    -
    11681  if(index == suballocations->size())
    -
    11682  {
    -
    11683  index = 0;
    -
    11684  // If we get to the end of 1st, we wrap around to beginning of 2nd of 1st.
    -
    11685  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    11686  {
    -
    11687  suballocations = &AccessSuballocations2nd();
    -
    11688  }
    -
    11689  // else: m_2ndVectorMode == SECOND_VECTOR_EMPTY:
    -
    11690  // suballocations continues pointing at AccessSuballocations1st().
    -
    11691  VMA_ASSERT(!suballocations->empty());
    -
    11692  }
    -
    11693  VmaSuballocation& suballoc = (*suballocations)[index];
    -
    11694  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    -
    11695  {
    -
    11696  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
    -
    11697  VMA_ASSERT(suballoc.hAllocation->CanBecomeLost());
    -
    11698  if(suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    -
    11699  {
    -
    11700  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    11701  suballoc.hAllocation = VK_NULL_HANDLE;
    -
    11702  m_SumFreeSize += suballoc.size;
    -
    11703  if(suballocations == &AccessSuballocations1st())
    -
    11704  {
    -
    11705  ++m_1stNullItemsMiddleCount;
    -
    11706  }
    -
    11707  else
    -
    11708  {
    -
    11709  ++m_2ndNullItemsCount;
    -
    11710  }
    -
    11711  ++madeLostCount;
    -
    11712  }
    -
    11713  else
    +
    11675  return false;
    +
    11676 }
    +
    11677 
    +
    11678 bool VmaBlockMetadata_Linear::MakeRequestedAllocationsLost(
    +
    11679  uint32_t currentFrameIndex,
    +
    11680  uint32_t frameInUseCount,
    +
    11681  VmaAllocationRequest* pAllocationRequest)
    +
    11682 {
    +
    11683  if(pAllocationRequest->itemsToMakeLostCount == 0)
    +
    11684  {
    +
    11685  return true;
    +
    11686  }
    +
    11687 
    +
    11688  VMA_ASSERT(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER);
    +
    11689 
    +
    11690  // We always start from 1st.
    +
    11691  SuballocationVectorType* suballocations = &AccessSuballocations1st();
    +
    11692  size_t index = m_1stNullItemsBeginCount;
    +
    11693  size_t madeLostCount = 0;
    +
    11694  while(madeLostCount < pAllocationRequest->itemsToMakeLostCount)
    +
    11695  {
    +
    11696  if(index == suballocations->size())
    +
    11697  {
    +
    11698  index = 0;
    +
    11699  // If we get to the end of 1st, we wrap around to beginning of 2nd of 1st.
    +
    11700  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    11701  {
    +
    11702  suballocations = &AccessSuballocations2nd();
    +
    11703  }
    +
    11704  // else: m_2ndVectorMode == SECOND_VECTOR_EMPTY:
    +
    11705  // suballocations continues pointing at AccessSuballocations1st().
    +
    11706  VMA_ASSERT(!suballocations->empty());
    +
    11707  }
    +
    11708  VmaSuballocation& suballoc = (*suballocations)[index];
    +
    11709  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    +
    11710  {
    +
    11711  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
    +
    11712  VMA_ASSERT(suballoc.hAllocation->CanBecomeLost());
    +
    11713  if(suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    11714  {
    -
    11715  return false;
    -
    11716  }
    -
    11717  }
    -
    11718  ++index;
    -
    11719  }
    -
    11720 
    -
    11721  CleanupAfterFree();
    -
    11722  //VMA_HEAVY_ASSERT(Validate()); // Already called by CleanupAfterFree().
    -
    11723 
    -
    11724  return true;
    -
    11725 }
    -
    11726 
    -
    11727 uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    -
    11728 {
    -
    11729  uint32_t lostAllocationCount = 0;
    -
    11730 
    -
    11731  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11732  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
    -
    11733  {
    -
    11734  VmaSuballocation& suballoc = suballocations1st[i];
    -
    11735  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
    -
    11736  suballoc.hAllocation->CanBecomeLost() &&
    -
    11737  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    -
    11738  {
    -
    11739  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    11740  suballoc.hAllocation = VK_NULL_HANDLE;
    -
    11741  ++m_1stNullItemsMiddleCount;
    -
    11742  m_SumFreeSize += suballoc.size;
    -
    11743  ++lostAllocationCount;
    -
    11744  }
    -
    11745  }
    -
    11746 
    -
    11747  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    11748  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
    -
    11749  {
    -
    11750  VmaSuballocation& suballoc = suballocations2nd[i];
    -
    11751  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
    -
    11752  suballoc.hAllocation->CanBecomeLost() &&
    -
    11753  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    -
    11754  {
    -
    11755  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    11756  suballoc.hAllocation = VK_NULL_HANDLE;
    -
    11757  ++m_2ndNullItemsCount;
    -
    11758  m_SumFreeSize += suballoc.size;
    -
    11759  ++lostAllocationCount;
    -
    11760  }
    -
    11761  }
    -
    11762 
    -
    11763  if(lostAllocationCount)
    +
    11715  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    11716  suballoc.hAllocation = VK_NULL_HANDLE;
    +
    11717  m_SumFreeSize += suballoc.size;
    +
    11718  if(suballocations == &AccessSuballocations1st())
    +
    11719  {
    +
    11720  ++m_1stNullItemsMiddleCount;
    +
    11721  }
    +
    11722  else
    +
    11723  {
    +
    11724  ++m_2ndNullItemsCount;
    +
    11725  }
    +
    11726  ++madeLostCount;
    +
    11727  }
    +
    11728  else
    +
    11729  {
    +
    11730  return false;
    +
    11731  }
    +
    11732  }
    +
    11733  ++index;
    +
    11734  }
    +
    11735 
    +
    11736  CleanupAfterFree();
    +
    11737  //VMA_HEAVY_ASSERT(Validate()); // Already called by CleanupAfterFree().
    +
    11738 
    +
    11739  return true;
    +
    11740 }
    +
    11741 
    +
    11742 uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    +
    11743 {
    +
    11744  uint32_t lostAllocationCount = 0;
    +
    11745 
    +
    11746  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11747  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
    +
    11748  {
    +
    11749  VmaSuballocation& suballoc = suballocations1st[i];
    +
    11750  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
    +
    11751  suballoc.hAllocation->CanBecomeLost() &&
    +
    11752  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    +
    11753  {
    +
    11754  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    11755  suballoc.hAllocation = VK_NULL_HANDLE;
    +
    11756  ++m_1stNullItemsMiddleCount;
    +
    11757  m_SumFreeSize += suballoc.size;
    +
    11758  ++lostAllocationCount;
    +
    11759  }
    +
    11760  }
    +
    11761 
    +
    11762  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11763  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
    11764  {
    -
    11765  CleanupAfterFree();
    -
    11766  }
    -
    11767 
    -
    11768  return lostAllocationCount;
    -
    11769 }
    -
    11770 
    -
    11771 VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData)
    -
    11772 {
    -
    11773  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11774  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
    -
    11775  {
    -
    11776  const VmaSuballocation& suballoc = suballocations1st[i];
    -
    11777  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    -
    11778  {
    -
    11779  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
    -
    11780  {
    -
    11781  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
    -
    11782  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    11783  }
    -
    11784  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
    -
    11785  {
    -
    11786  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
    -
    11787  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    11788  }
    -
    11789  }
    -
    11790  }
    -
    11791 
    -
    11792  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    11793  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
    -
    11794  {
    -
    11795  const VmaSuballocation& suballoc = suballocations2nd[i];
    -
    11796  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    -
    11797  {
    -
    11798  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
    -
    11799  {
    -
    11800  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
    -
    11801  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    11802  }
    -
    11803  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
    -
    11804  {
    -
    11805  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
    -
    11806  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    11807  }
    -
    11808  }
    -
    11809  }
    -
    11810 
    -
    11811  return VK_SUCCESS;
    -
    11812 }
    -
    11813 
    -
    11814 void VmaBlockMetadata_Linear::Alloc(
    -
    11815  const VmaAllocationRequest& request,
    -
    11816  VmaSuballocationType type,
    -
    11817  VkDeviceSize allocSize,
    -
    11818  VmaAllocation hAllocation)
    -
    11819 {
    -
    11820  const VmaSuballocation newSuballoc = { request.offset, allocSize, hAllocation, type };
    -
    11821 
    -
    11822  switch(request.type)
    -
    11823  {
    -
    11824  case VmaAllocationRequestType::UpperAddress:
    -
    11825  {
    -
    11826  VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER &&
    -
    11827  "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer.");
    -
    11828  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    11829  suballocations2nd.push_back(newSuballoc);
    -
    11830  m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK;
    -
    11831  }
    -
    11832  break;
    -
    11833  case VmaAllocationRequestType::EndOf1st:
    -
    11834  {
    -
    11835  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11765  VmaSuballocation& suballoc = suballocations2nd[i];
    +
    11766  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
    +
    11767  suballoc.hAllocation->CanBecomeLost() &&
    +
    11768  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
    +
    11769  {
    +
    11770  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    11771  suballoc.hAllocation = VK_NULL_HANDLE;
    +
    11772  ++m_2ndNullItemsCount;
    +
    11773  m_SumFreeSize += suballoc.size;
    +
    11774  ++lostAllocationCount;
    +
    11775  }
    +
    11776  }
    +
    11777 
    +
    11778  if(lostAllocationCount)
    +
    11779  {
    +
    11780  CleanupAfterFree();
    +
    11781  }
    +
    11782 
    +
    11783  return lostAllocationCount;
    +
    11784 }
    +
    11785 
    +
    11786 VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData)
    +
    11787 {
    +
    11788  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11789  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
    +
    11790  {
    +
    11791  const VmaSuballocation& suballoc = suballocations1st[i];
    +
    11792  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    +
    11793  {
    +
    11794  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
    +
    11795  {
    +
    11796  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
    +
    11797  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    11798  }
    +
    11799  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
    +
    11800  {
    +
    11801  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
    +
    11802  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    11803  }
    +
    11804  }
    +
    11805  }
    +
    11806 
    +
    11807  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11808  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
    +
    11809  {
    +
    11810  const VmaSuballocation& suballoc = suballocations2nd[i];
    +
    11811  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    +
    11812  {
    +
    11813  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
    +
    11814  {
    +
    11815  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
    +
    11816  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    11817  }
    +
    11818  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
    +
    11819  {
    +
    11820  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
    +
    11821  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    11822  }
    +
    11823  }
    +
    11824  }
    +
    11825 
    +
    11826  return VK_SUCCESS;
    +
    11827 }
    +
    11828 
    +
    11829 void VmaBlockMetadata_Linear::Alloc(
    +
    11830  const VmaAllocationRequest& request,
    +
    11831  VmaSuballocationType type,
    +
    11832  VkDeviceSize allocSize,
    +
    11833  VmaAllocation hAllocation)
    +
    11834 {
    +
    11835  const VmaSuballocation newSuballoc = { request.offset, allocSize, hAllocation, type };
    11836 
    -
    11837  VMA_ASSERT(suballocations1st.empty() ||
    -
    11838  request.offset >= suballocations1st.back().offset + suballocations1st.back().size);
    -
    11839  // Check if it fits before the end of the block.
    -
    11840  VMA_ASSERT(request.offset + allocSize <= GetSize());
    -
    11841 
    -
    11842  suballocations1st.push_back(newSuballoc);
    -
    11843  }
    -
    11844  break;
    -
    11845  case VmaAllocationRequestType::EndOf2nd:
    -
    11846  {
    -
    11847  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11848  // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector.
    -
    11849  VMA_ASSERT(!suballocations1st.empty() &&
    -
    11850  request.offset + allocSize <= suballocations1st[m_1stNullItemsBeginCount].offset);
    -
    11851  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    11852 
    -
    11853  switch(m_2ndVectorMode)
    -
    11854  {
    -
    11855  case SECOND_VECTOR_EMPTY:
    -
    11856  // First allocation from second part ring buffer.
    -
    11857  VMA_ASSERT(suballocations2nd.empty());
    -
    11858  m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER;
    -
    11859  break;
    -
    11860  case SECOND_VECTOR_RING_BUFFER:
    -
    11861  // 2-part ring buffer is already started.
    -
    11862  VMA_ASSERT(!suballocations2nd.empty());
    -
    11863  break;
    -
    11864  case SECOND_VECTOR_DOUBLE_STACK:
    -
    11865  VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack.");
    -
    11866  break;
    -
    11867  default:
    -
    11868  VMA_ASSERT(0);
    -
    11869  }
    -
    11870 
    -
    11871  suballocations2nd.push_back(newSuballoc);
    -
    11872  }
    -
    11873  break;
    -
    11874  default:
    -
    11875  VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR.");
    -
    11876  }
    -
    11877 
    -
    11878  m_SumFreeSize -= newSuballoc.size;
    -
    11879 }
    -
    11880 
    -
    11881 void VmaBlockMetadata_Linear::Free(const VmaAllocation allocation)
    -
    11882 {
    -
    11883  FreeAtOffset(allocation->GetOffset());
    -
    11884 }
    +
    11837  switch(request.type)
    +
    11838  {
    +
    11839  case VmaAllocationRequestType::UpperAddress:
    +
    11840  {
    +
    11841  VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER &&
    +
    11842  "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer.");
    +
    11843  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11844  suballocations2nd.push_back(newSuballoc);
    +
    11845  m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK;
    +
    11846  }
    +
    11847  break;
    +
    11848  case VmaAllocationRequestType::EndOf1st:
    +
    11849  {
    +
    11850  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11851 
    +
    11852  VMA_ASSERT(suballocations1st.empty() ||
    +
    11853  request.offset >= suballocations1st.back().offset + suballocations1st.back().size);
    +
    11854  // Check if it fits before the end of the block.
    +
    11855  VMA_ASSERT(request.offset + allocSize <= GetSize());
    +
    11856 
    +
    11857  suballocations1st.push_back(newSuballoc);
    +
    11858  }
    +
    11859  break;
    +
    11860  case VmaAllocationRequestType::EndOf2nd:
    +
    11861  {
    +
    11862  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11863  // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector.
    +
    11864  VMA_ASSERT(!suballocations1st.empty() &&
    +
    11865  request.offset + allocSize <= suballocations1st[m_1stNullItemsBeginCount].offset);
    +
    11866  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11867 
    +
    11868  switch(m_2ndVectorMode)
    +
    11869  {
    +
    11870  case SECOND_VECTOR_EMPTY:
    +
    11871  // First allocation from second part ring buffer.
    +
    11872  VMA_ASSERT(suballocations2nd.empty());
    +
    11873  m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER;
    +
    11874  break;
    +
    11875  case SECOND_VECTOR_RING_BUFFER:
    +
    11876  // 2-part ring buffer is already started.
    +
    11877  VMA_ASSERT(!suballocations2nd.empty());
    +
    11878  break;
    +
    11879  case SECOND_VECTOR_DOUBLE_STACK:
    +
    11880  VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack.");
    +
    11881  break;
    +
    11882  default:
    +
    11883  VMA_ASSERT(0);
    +
    11884  }
    11885 
    -
    11886 void VmaBlockMetadata_Linear::FreeAtOffset(VkDeviceSize offset)
    -
    11887 {
    -
    11888  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11889  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    -
    11890 
    -
    11891  if(!suballocations1st.empty())
    -
    11892  {
    -
    11893  // First allocation: Mark it as next empty at the beginning.
    -
    11894  VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
    -
    11895  if(firstSuballoc.offset == offset)
    -
    11896  {
    -
    11897  firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    11898  firstSuballoc.hAllocation = VK_NULL_HANDLE;
    -
    11899  m_SumFreeSize += firstSuballoc.size;
    -
    11900  ++m_1stNullItemsBeginCount;
    -
    11901  CleanupAfterFree();
    -
    11902  return;
    -
    11903  }
    -
    11904  }
    +
    11886  suballocations2nd.push_back(newSuballoc);
    +
    11887  }
    +
    11888  break;
    +
    11889  default:
    +
    11890  VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR.");
    +
    11891  }
    +
    11892 
    +
    11893  m_SumFreeSize -= newSuballoc.size;
    +
    11894 }
    +
    11895 
    +
    11896 void VmaBlockMetadata_Linear::Free(const VmaAllocation allocation)
    +
    11897 {
    +
    11898  FreeAtOffset(allocation->GetOffset());
    +
    11899 }
    +
    11900 
    +
    11901 void VmaBlockMetadata_Linear::FreeAtOffset(VkDeviceSize offset)
    +
    11902 {
    +
    11903  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    11904  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    11905 
    -
    11906  // Last allocation in 2-part ring buffer or top of upper stack (same logic).
    -
    11907  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ||
    -
    11908  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    -
    11909  {
    -
    11910  VmaSuballocation& lastSuballoc = suballocations2nd.back();
    -
    11911  if(lastSuballoc.offset == offset)
    -
    11912  {
    -
    11913  m_SumFreeSize += lastSuballoc.size;
    -
    11914  suballocations2nd.pop_back();
    -
    11915  CleanupAfterFree();
    -
    11916  return;
    -
    11917  }
    -
    11918  }
    -
    11919  // Last allocation in 1st vector.
    -
    11920  else if(m_2ndVectorMode == SECOND_VECTOR_EMPTY)
    -
    11921  {
    -
    11922  VmaSuballocation& lastSuballoc = suballocations1st.back();
    -
    11923  if(lastSuballoc.offset == offset)
    -
    11924  {
    -
    11925  m_SumFreeSize += lastSuballoc.size;
    -
    11926  suballocations1st.pop_back();
    -
    11927  CleanupAfterFree();
    -
    11928  return;
    -
    11929  }
    -
    11930  }
    -
    11931 
    -
    11932  // Item from the middle of 1st vector.
    -
    11933  {
    -
    11934  VmaSuballocation refSuballoc;
    -
    11935  refSuballoc.offset = offset;
    -
    11936  // Rest of members stays uninitialized intentionally for better performance.
    -
    11937  SuballocationVectorType::iterator it = VmaBinaryFindSorted(
    -
    11938  suballocations1st.begin() + m_1stNullItemsBeginCount,
    -
    11939  suballocations1st.end(),
    -
    11940  refSuballoc,
    -
    11941  VmaSuballocationOffsetLess());
    -
    11942  if(it != suballocations1st.end())
    -
    11943  {
    -
    11944  it->type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    11945  it->hAllocation = VK_NULL_HANDLE;
    -
    11946  ++m_1stNullItemsMiddleCount;
    -
    11947  m_SumFreeSize += it->size;
    -
    11948  CleanupAfterFree();
    -
    11949  return;
    -
    11950  }
    -
    11951  }
    -
    11952 
    -
    11953  if(m_2ndVectorMode != SECOND_VECTOR_EMPTY)
    -
    11954  {
    -
    11955  // Item from the middle of 2nd vector.
    -
    11956  VmaSuballocation refSuballoc;
    -
    11957  refSuballoc.offset = offset;
    -
    11958  // Rest of members stays uninitialized intentionally for better performance.
    -
    11959  SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
    -
    11960  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) :
    -
    11961  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater());
    -
    11962  if(it != suballocations2nd.end())
    -
    11963  {
    -
    11964  it->type = VMA_SUBALLOCATION_TYPE_FREE;
    -
    11965  it->hAllocation = VK_NULL_HANDLE;
    -
    11966  ++m_2ndNullItemsCount;
    -
    11967  m_SumFreeSize += it->size;
    -
    11968  CleanupAfterFree();
    -
    11969  return;
    -
    11970  }
    -
    11971  }
    -
    11972 
    -
    11973  VMA_ASSERT(0 && "Allocation to free not found in linear allocator!");
    -
    11974 }
    -
    11975 
    -
    11976 bool VmaBlockMetadata_Linear::ShouldCompact1st() const
    -
    11977 {
    -
    11978  const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
    -
    11979  const size_t suballocCount = AccessSuballocations1st().size();
    -
    11980  return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3;
    -
    11981 }
    -
    11982 
    -
    11983 void VmaBlockMetadata_Linear::CleanupAfterFree()
    -
    11984 {
    -
    11985  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    -
    11986  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    +
    11906  if(!suballocations1st.empty())
    +
    11907  {
    +
    11908  // First allocation: Mark it as next empty at the beginning.
    +
    11909  VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
    +
    11910  if(firstSuballoc.offset == offset)
    +
    11911  {
    +
    11912  firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    11913  firstSuballoc.hAllocation = VK_NULL_HANDLE;
    +
    11914  m_SumFreeSize += firstSuballoc.size;
    +
    11915  ++m_1stNullItemsBeginCount;
    +
    11916  CleanupAfterFree();
    +
    11917  return;
    +
    11918  }
    +
    11919  }
    +
    11920 
    +
    11921  // Last allocation in 2-part ring buffer or top of upper stack (same logic).
    +
    11922  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ||
    +
    11923  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
    +
    11924  {
    +
    11925  VmaSuballocation& lastSuballoc = suballocations2nd.back();
    +
    11926  if(lastSuballoc.offset == offset)
    +
    11927  {
    +
    11928  m_SumFreeSize += lastSuballoc.size;
    +
    11929  suballocations2nd.pop_back();
    +
    11930  CleanupAfterFree();
    +
    11931  return;
    +
    11932  }
    +
    11933  }
    +
    11934  // Last allocation in 1st vector.
    +
    11935  else if(m_2ndVectorMode == SECOND_VECTOR_EMPTY)
    +
    11936  {
    +
    11937  VmaSuballocation& lastSuballoc = suballocations1st.back();
    +
    11938  if(lastSuballoc.offset == offset)
    +
    11939  {
    +
    11940  m_SumFreeSize += lastSuballoc.size;
    +
    11941  suballocations1st.pop_back();
    +
    11942  CleanupAfterFree();
    +
    11943  return;
    +
    11944  }
    +
    11945  }
    +
    11946 
    +
    11947  // Item from the middle of 1st vector.
    +
    11948  {
    +
    11949  VmaSuballocation refSuballoc;
    +
    11950  refSuballoc.offset = offset;
    +
    11951  // Rest of members stays uninitialized intentionally for better performance.
    +
    11952  SuballocationVectorType::iterator it = VmaBinaryFindSorted(
    +
    11953  suballocations1st.begin() + m_1stNullItemsBeginCount,
    +
    11954  suballocations1st.end(),
    +
    11955  refSuballoc,
    +
    11956  VmaSuballocationOffsetLess());
    +
    11957  if(it != suballocations1st.end())
    +
    11958  {
    +
    11959  it->type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    11960  it->hAllocation = VK_NULL_HANDLE;
    +
    11961  ++m_1stNullItemsMiddleCount;
    +
    11962  m_SumFreeSize += it->size;
    +
    11963  CleanupAfterFree();
    +
    11964  return;
    +
    11965  }
    +
    11966  }
    +
    11967 
    +
    11968  if(m_2ndVectorMode != SECOND_VECTOR_EMPTY)
    +
    11969  {
    +
    11970  // Item from the middle of 2nd vector.
    +
    11971  VmaSuballocation refSuballoc;
    +
    11972  refSuballoc.offset = offset;
    +
    11973  // Rest of members stays uninitialized intentionally for better performance.
    +
    11974  SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
    +
    11975  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) :
    +
    11976  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater());
    +
    11977  if(it != suballocations2nd.end())
    +
    11978  {
    +
    11979  it->type = VMA_SUBALLOCATION_TYPE_FREE;
    +
    11980  it->hAllocation = VK_NULL_HANDLE;
    +
    11981  ++m_2ndNullItemsCount;
    +
    11982  m_SumFreeSize += it->size;
    +
    11983  CleanupAfterFree();
    +
    11984  return;
    +
    11985  }
    +
    11986  }
    11987 
    -
    11988  if(IsEmpty())
    -
    11989  {
    -
    11990  suballocations1st.clear();
    -
    11991  suballocations2nd.clear();
    -
    11992  m_1stNullItemsBeginCount = 0;
    -
    11993  m_1stNullItemsMiddleCount = 0;
    -
    11994  m_2ndNullItemsCount = 0;
    -
    11995  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
    -
    11996  }
    -
    11997  else
    -
    11998  {
    -
    11999  const size_t suballoc1stCount = suballocations1st.size();
    -
    12000  const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
    -
    12001  VMA_ASSERT(nullItem1stCount <= suballoc1stCount);
    +
    11988  VMA_ASSERT(0 && "Allocation to free not found in linear allocator!");
    +
    11989 }
    +
    11990 
    +
    11991 bool VmaBlockMetadata_Linear::ShouldCompact1st() const
    +
    11992 {
    +
    11993  const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
    +
    11994  const size_t suballocCount = AccessSuballocations1st().size();
    +
    11995  return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3;
    +
    11996 }
    +
    11997 
    +
    11998 void VmaBlockMetadata_Linear::CleanupAfterFree()
    +
    11999 {
    +
    12000  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
    +
    12001  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
    12002 
    -
    12003  // Find more null items at the beginning of 1st vector.
    -
    12004  while(m_1stNullItemsBeginCount < suballoc1stCount &&
    -
    12005  suballocations1st[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
    -
    12006  {
    -
    12007  ++m_1stNullItemsBeginCount;
    -
    12008  --m_1stNullItemsMiddleCount;
    -
    12009  }
    -
    12010 
    -
    12011  // Find more null items at the end of 1st vector.
    -
    12012  while(m_1stNullItemsMiddleCount > 0 &&
    -
    12013  suballocations1st.back().hAllocation == VK_NULL_HANDLE)
    -
    12014  {
    -
    12015  --m_1stNullItemsMiddleCount;
    -
    12016  suballocations1st.pop_back();
    -
    12017  }
    -
    12018 
    -
    12019  // Find more null items at the end of 2nd vector.
    -
    12020  while(m_2ndNullItemsCount > 0 &&
    -
    12021  suballocations2nd.back().hAllocation == VK_NULL_HANDLE)
    -
    12022  {
    -
    12023  --m_2ndNullItemsCount;
    -
    12024  suballocations2nd.pop_back();
    -
    12025  }
    -
    12026 
    -
    12027  // Find more null items at the beginning of 2nd vector.
    -
    12028  while(m_2ndNullItemsCount > 0 &&
    -
    12029  suballocations2nd[0].hAllocation == VK_NULL_HANDLE)
    -
    12030  {
    -
    12031  --m_2ndNullItemsCount;
    -
    12032  VmaVectorRemove(suballocations2nd, 0);
    -
    12033  }
    -
    12034 
    -
    12035  if(ShouldCompact1st())
    -
    12036  {
    -
    12037  const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount;
    -
    12038  size_t srcIndex = m_1stNullItemsBeginCount;
    -
    12039  for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
    -
    12040  {
    -
    12041  while(suballocations1st[srcIndex].hAllocation == VK_NULL_HANDLE)
    -
    12042  {
    -
    12043  ++srcIndex;
    -
    12044  }
    -
    12045  if(dstIndex != srcIndex)
    -
    12046  {
    -
    12047  suballocations1st[dstIndex] = suballocations1st[srcIndex];
    -
    12048  }
    -
    12049  ++srcIndex;
    -
    12050  }
    -
    12051  suballocations1st.resize(nonNullItemCount);
    -
    12052  m_1stNullItemsBeginCount = 0;
    -
    12053  m_1stNullItemsMiddleCount = 0;
    -
    12054  }
    -
    12055 
    -
    12056  // 2nd vector became empty.
    -
    12057  if(suballocations2nd.empty())
    -
    12058  {
    -
    12059  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
    -
    12060  }
    -
    12061 
    -
    12062  // 1st vector became empty.
    -
    12063  if(suballocations1st.size() - m_1stNullItemsBeginCount == 0)
    -
    12064  {
    -
    12065  suballocations1st.clear();
    -
    12066  m_1stNullItemsBeginCount = 0;
    -
    12067 
    -
    12068  if(!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    -
    12069  {
    -
    12070  // Swap 1st with 2nd. Now 2nd is empty.
    -
    12071  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
    -
    12072  m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
    -
    12073  while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
    -
    12074  suballocations2nd[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
    -
    12075  {
    -
    12076  ++m_1stNullItemsBeginCount;
    -
    12077  --m_1stNullItemsMiddleCount;
    -
    12078  }
    -
    12079  m_2ndNullItemsCount = 0;
    -
    12080  m_1stVectorIndex ^= 1;
    -
    12081  }
    -
    12082  }
    -
    12083  }
    -
    12084 
    -
    12085  VMA_HEAVY_ASSERT(Validate());
    -
    12086 }
    -
    12087 
    -
    12088 
    -
    12090 // class VmaBlockMetadata_Buddy
    -
    12091 
    -
    12092 VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) :
    -
    12093  VmaBlockMetadata(hAllocator),
    -
    12094  m_Root(VMA_NULL),
    -
    12095  m_AllocationCount(0),
    -
    12096  m_FreeCount(1),
    -
    12097  m_SumFreeSize(0)
    -
    12098 {
    -
    12099  memset(m_FreeList, 0, sizeof(m_FreeList));
    -
    12100 }
    -
    12101 
    -
    12102 VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy()
    -
    12103 {
    -
    12104  DeleteNode(m_Root);
    -
    12105 }
    +
    12003  if(IsEmpty())
    +
    12004  {
    +
    12005  suballocations1st.clear();
    +
    12006  suballocations2nd.clear();
    +
    12007  m_1stNullItemsBeginCount = 0;
    +
    12008  m_1stNullItemsMiddleCount = 0;
    +
    12009  m_2ndNullItemsCount = 0;
    +
    12010  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
    +
    12011  }
    +
    12012  else
    +
    12013  {
    +
    12014  const size_t suballoc1stCount = suballocations1st.size();
    +
    12015  const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
    +
    12016  VMA_ASSERT(nullItem1stCount <= suballoc1stCount);
    +
    12017 
    +
    12018  // Find more null items at the beginning of 1st vector.
    +
    12019  while(m_1stNullItemsBeginCount < suballoc1stCount &&
    +
    12020  suballocations1st[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
    +
    12021  {
    +
    12022  ++m_1stNullItemsBeginCount;
    +
    12023  --m_1stNullItemsMiddleCount;
    +
    12024  }
    +
    12025 
    +
    12026  // Find more null items at the end of 1st vector.
    +
    12027  while(m_1stNullItemsMiddleCount > 0 &&
    +
    12028  suballocations1st.back().hAllocation == VK_NULL_HANDLE)
    +
    12029  {
    +
    12030  --m_1stNullItemsMiddleCount;
    +
    12031  suballocations1st.pop_back();
    +
    12032  }
    +
    12033 
    +
    12034  // Find more null items at the end of 2nd vector.
    +
    12035  while(m_2ndNullItemsCount > 0 &&
    +
    12036  suballocations2nd.back().hAllocation == VK_NULL_HANDLE)
    +
    12037  {
    +
    12038  --m_2ndNullItemsCount;
    +
    12039  suballocations2nd.pop_back();
    +
    12040  }
    +
    12041 
    +
    12042  // Find more null items at the beginning of 2nd vector.
    +
    12043  while(m_2ndNullItemsCount > 0 &&
    +
    12044  suballocations2nd[0].hAllocation == VK_NULL_HANDLE)
    +
    12045  {
    +
    12046  --m_2ndNullItemsCount;
    +
    12047  VmaVectorRemove(suballocations2nd, 0);
    +
    12048  }
    +
    12049 
    +
    12050  if(ShouldCompact1st())
    +
    12051  {
    +
    12052  const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount;
    +
    12053  size_t srcIndex = m_1stNullItemsBeginCount;
    +
    12054  for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
    +
    12055  {
    +
    12056  while(suballocations1st[srcIndex].hAllocation == VK_NULL_HANDLE)
    +
    12057  {
    +
    12058  ++srcIndex;
    +
    12059  }
    +
    12060  if(dstIndex != srcIndex)
    +
    12061  {
    +
    12062  suballocations1st[dstIndex] = suballocations1st[srcIndex];
    +
    12063  }
    +
    12064  ++srcIndex;
    +
    12065  }
    +
    12066  suballocations1st.resize(nonNullItemCount);
    +
    12067  m_1stNullItemsBeginCount = 0;
    +
    12068  m_1stNullItemsMiddleCount = 0;
    +
    12069  }
    +
    12070 
    +
    12071  // 2nd vector became empty.
    +
    12072  if(suballocations2nd.empty())
    +
    12073  {
    +
    12074  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
    +
    12075  }
    +
    12076 
    +
    12077  // 1st vector became empty.
    +
    12078  if(suballocations1st.size() - m_1stNullItemsBeginCount == 0)
    +
    12079  {
    +
    12080  suballocations1st.clear();
    +
    12081  m_1stNullItemsBeginCount = 0;
    +
    12082 
    +
    12083  if(!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
    +
    12084  {
    +
    12085  // Swap 1st with 2nd. Now 2nd is empty.
    +
    12086  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
    +
    12087  m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
    +
    12088  while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
    +
    12089  suballocations2nd[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
    +
    12090  {
    +
    12091  ++m_1stNullItemsBeginCount;
    +
    12092  --m_1stNullItemsMiddleCount;
    +
    12093  }
    +
    12094  m_2ndNullItemsCount = 0;
    +
    12095  m_1stVectorIndex ^= 1;
    +
    12096  }
    +
    12097  }
    +
    12098  }
    +
    12099 
    +
    12100  VMA_HEAVY_ASSERT(Validate());
    +
    12101 }
    +
    12102 
    +
    12103 
    +
    12105 // class VmaBlockMetadata_Buddy
    12106 
    -
    12107 void VmaBlockMetadata_Buddy::Init(VkDeviceSize size)
    -
    12108 {
    -
    12109  VmaBlockMetadata::Init(size);
    -
    12110 
    -
    12111  m_UsableSize = VmaPrevPow2(size);
    -
    12112  m_SumFreeSize = m_UsableSize;
    -
    12113 
    -
    12114  // Calculate m_LevelCount.
    -
    12115  m_LevelCount = 1;
    -
    12116  while(m_LevelCount < MAX_LEVELS &&
    -
    12117  LevelToNodeSize(m_LevelCount) >= MIN_NODE_SIZE)
    -
    12118  {
    -
    12119  ++m_LevelCount;
    -
    12120  }
    +
    12107 VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) :
    +
    12108  VmaBlockMetadata(hAllocator),
    +
    12109  m_Root(VMA_NULL),
    +
    12110  m_AllocationCount(0),
    +
    12111  m_FreeCount(1),
    +
    12112  m_SumFreeSize(0)
    +
    12113 {
    +
    12114  memset(m_FreeList, 0, sizeof(m_FreeList));
    +
    12115 }
    +
    12116 
    +
    12117 VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy()
    +
    12118 {
    +
    12119  DeleteNode(m_Root);
    +
    12120 }
    12121 
    -
    12122  Node* rootNode = vma_new(GetAllocationCallbacks(), Node)();
    -
    12123  rootNode->offset = 0;
    -
    12124  rootNode->type = Node::TYPE_FREE;
    -
    12125  rootNode->parent = VMA_NULL;
    -
    12126  rootNode->buddy = VMA_NULL;
    -
    12127 
    -
    12128  m_Root = rootNode;
    -
    12129  AddToFreeListFront(0, rootNode);
    -
    12130 }
    -
    12131 
    -
    12132 bool VmaBlockMetadata_Buddy::Validate() const
    -
    12133 {
    -
    12134  // Validate tree.
    -
    12135  ValidationContext ctx;
    -
    12136  if(!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0)))
    -
    12137  {
    -
    12138  VMA_VALIDATE(false && "ValidateNode failed.");
    -
    12139  }
    -
    12140  VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount);
    -
    12141  VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize);
    +
    12122 void VmaBlockMetadata_Buddy::Init(VkDeviceSize size)
    +
    12123 {
    +
    12124  VmaBlockMetadata::Init(size);
    +
    12125 
    +
    12126  m_UsableSize = VmaPrevPow2(size);
    +
    12127  m_SumFreeSize = m_UsableSize;
    +
    12128 
    +
    12129  // Calculate m_LevelCount.
    +
    12130  m_LevelCount = 1;
    +
    12131  while(m_LevelCount < MAX_LEVELS &&
    +
    12132  LevelToNodeSize(m_LevelCount) >= MIN_NODE_SIZE)
    +
    12133  {
    +
    12134  ++m_LevelCount;
    +
    12135  }
    +
    12136 
    +
    12137  Node* rootNode = vma_new(GetAllocationCallbacks(), Node)();
    +
    12138  rootNode->offset = 0;
    +
    12139  rootNode->type = Node::TYPE_FREE;
    +
    12140  rootNode->parent = VMA_NULL;
    +
    12141  rootNode->buddy = VMA_NULL;
    12142 
    -
    12143  // Validate free node lists.
    -
    12144  for(uint32_t level = 0; level < m_LevelCount; ++level)
    -
    12145  {
    -
    12146  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL ||
    -
    12147  m_FreeList[level].front->free.prev == VMA_NULL);
    -
    12148 
    -
    12149  for(Node* node = m_FreeList[level].front;
    -
    12150  node != VMA_NULL;
    -
    12151  node = node->free.next)
    -
    12152  {
    -
    12153  VMA_VALIDATE(node->type == Node::TYPE_FREE);
    -
    12154 
    -
    12155  if(node->free.next == VMA_NULL)
    -
    12156  {
    -
    12157  VMA_VALIDATE(m_FreeList[level].back == node);
    -
    12158  }
    -
    12159  else
    -
    12160  {
    -
    12161  VMA_VALIDATE(node->free.next->free.prev == node);
    -
    12162  }
    -
    12163  }
    -
    12164  }
    -
    12165 
    -
    12166  // Validate that free lists ar higher levels are empty.
    -
    12167  for(uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level)
    -
    12168  {
    -
    12169  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL);
    -
    12170  }
    -
    12171 
    -
    12172  return true;
    -
    12173 }
    -
    12174 
    -
    12175 VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const
    -
    12176 {
    -
    12177  for(uint32_t level = 0; level < m_LevelCount; ++level)
    -
    12178  {
    -
    12179  if(m_FreeList[level].front != VMA_NULL)
    -
    12180  {
    -
    12181  return LevelToNodeSize(level);
    -
    12182  }
    -
    12183  }
    -
    12184  return 0;
    -
    12185 }
    +
    12143  m_Root = rootNode;
    +
    12144  AddToFreeListFront(0, rootNode);
    +
    12145 }
    +
    12146 
    +
    12147 bool VmaBlockMetadata_Buddy::Validate() const
    +
    12148 {
    +
    12149  // Validate tree.
    +
    12150  ValidationContext ctx;
    +
    12151  if(!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0)))
    +
    12152  {
    +
    12153  VMA_VALIDATE(false && "ValidateNode failed.");
    +
    12154  }
    +
    12155  VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount);
    +
    12156  VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize);
    +
    12157 
    +
    12158  // Validate free node lists.
    +
    12159  for(uint32_t level = 0; level < m_LevelCount; ++level)
    +
    12160  {
    +
    12161  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL ||
    +
    12162  m_FreeList[level].front->free.prev == VMA_NULL);
    +
    12163 
    +
    12164  for(Node* node = m_FreeList[level].front;
    +
    12165  node != VMA_NULL;
    +
    12166  node = node->free.next)
    +
    12167  {
    +
    12168  VMA_VALIDATE(node->type == Node::TYPE_FREE);
    +
    12169 
    +
    12170  if(node->free.next == VMA_NULL)
    +
    12171  {
    +
    12172  VMA_VALIDATE(m_FreeList[level].back == node);
    +
    12173  }
    +
    12174  else
    +
    12175  {
    +
    12176  VMA_VALIDATE(node->free.next->free.prev == node);
    +
    12177  }
    +
    12178  }
    +
    12179  }
    +
    12180 
    +
    12181  // Validate that free lists ar higher levels are empty.
    +
    12182  for(uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level)
    +
    12183  {
    +
    12184  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL);
    +
    12185  }
    12186 
    -
    12187 void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
    -
    12188 {
    -
    12189  const VkDeviceSize unusableSize = GetUnusableSize();
    -
    12190 
    -
    12191  outInfo.blockCount = 1;
    -
    12192 
    -
    12193  outInfo.allocationCount = outInfo.unusedRangeCount = 0;
    -
    12194  outInfo.usedBytes = outInfo.unusedBytes = 0;
    -
    12195 
    -
    12196  outInfo.allocationSizeMax = outInfo.unusedRangeSizeMax = 0;
    -
    12197  outInfo.allocationSizeMin = outInfo.unusedRangeSizeMin = UINT64_MAX;
    -
    12198  outInfo.allocationSizeAvg = outInfo.unusedRangeSizeAvg = 0; // Unused.
    -
    12199 
    -
    12200  CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));
    +
    12187  return true;
    +
    12188 }
    +
    12189 
    +
    12190 VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const
    +
    12191 {
    +
    12192  for(uint32_t level = 0; level < m_LevelCount; ++level)
    +
    12193  {
    +
    12194  if(m_FreeList[level].front != VMA_NULL)
    +
    12195  {
    +
    12196  return LevelToNodeSize(level);
    +
    12197  }
    +
    12198  }
    +
    12199  return 0;
    +
    12200 }
    12201 
    -
    12202  if(unusableSize > 0)
    -
    12203  {
    -
    12204  ++outInfo.unusedRangeCount;
    -
    12205  outInfo.unusedBytes += unusableSize;
    -
    12206  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusableSize);
    -
    12207  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusableSize);
    -
    12208  }
    -
    12209 }
    +
    12202 void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
    +
    12203 {
    +
    12204  const VkDeviceSize unusableSize = GetUnusableSize();
    +
    12205 
    +
    12206  outInfo.blockCount = 1;
    +
    12207 
    +
    12208  outInfo.allocationCount = outInfo.unusedRangeCount = 0;
    +
    12209  outInfo.usedBytes = outInfo.unusedBytes = 0;
    12210 
    -
    12211 void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const
    -
    12212 {
    -
    12213  const VkDeviceSize unusableSize = GetUnusableSize();
    +
    12211  outInfo.allocationSizeMax = outInfo.unusedRangeSizeMax = 0;
    +
    12212  outInfo.allocationSizeMin = outInfo.unusedRangeSizeMin = UINT64_MAX;
    +
    12213  outInfo.allocationSizeAvg = outInfo.unusedRangeSizeAvg = 0; // Unused.
    12214 
    -
    12215  inoutStats.size += GetSize();
    -
    12216  inoutStats.unusedSize += m_SumFreeSize + unusableSize;
    -
    12217  inoutStats.allocationCount += m_AllocationCount;
    -
    12218  inoutStats.unusedRangeCount += m_FreeCount;
    -
    12219  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
    -
    12220 
    -
    12221  if(unusableSize > 0)
    -
    12222  {
    -
    12223  ++inoutStats.unusedRangeCount;
    -
    12224  // Not updating inoutStats.unusedRangeSizeMax with unusableSize because this space is not available for allocations.
    -
    12225  }
    -
    12226 }
    -
    12227 
    -
    12228 #if VMA_STATS_STRING_ENABLED
    +
    12215  CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));
    +
    12216 
    +
    12217  if(unusableSize > 0)
    +
    12218  {
    +
    12219  ++outInfo.unusedRangeCount;
    +
    12220  outInfo.unusedBytes += unusableSize;
    +
    12221  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusableSize);
    +
    12222  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusableSize);
    +
    12223  }
    +
    12224 }
    +
    12225 
    +
    12226 void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const
    +
    12227 {
    +
    12228  const VkDeviceSize unusableSize = GetUnusableSize();
    12229 
    -
    12230 void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const
    -
    12231 {
    -
    12232  // TODO optimize
    -
    12233  VmaStatInfo stat;
    -
    12234  CalcAllocationStatInfo(stat);
    +
    12230  inoutStats.size += GetSize();
    +
    12231  inoutStats.unusedSize += m_SumFreeSize + unusableSize;
    +
    12232  inoutStats.allocationCount += m_AllocationCount;
    +
    12233  inoutStats.unusedRangeCount += m_FreeCount;
    +
    12234  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
    12235 
    -
    12236  PrintDetailedMap_Begin(
    -
    12237  json,
    -
    12238  stat.unusedBytes,
    -
    12239  stat.allocationCount,
    -
    12240  stat.unusedRangeCount);
    -
    12241 
    -
    12242  PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0));
    -
    12243 
    -
    12244  const VkDeviceSize unusableSize = GetUnusableSize();
    -
    12245  if(unusableSize > 0)
    -
    12246  {
    -
    12247  PrintDetailedMap_UnusedRange(json,
    -
    12248  m_UsableSize, // offset
    -
    12249  unusableSize); // size
    -
    12250  }
    -
    12251 
    -
    12252  PrintDetailedMap_End(json);
    -
    12253 }
    -
    12254 
    -
    12255 #endif // #if VMA_STATS_STRING_ENABLED
    +
    12236  if(unusableSize > 0)
    +
    12237  {
    +
    12238  ++inoutStats.unusedRangeCount;
    +
    12239  // Not updating inoutStats.unusedRangeSizeMax with unusableSize because this space is not available for allocations.
    +
    12240  }
    +
    12241 }
    +
    12242 
    +
    12243 #if VMA_STATS_STRING_ENABLED
    +
    12244 
    +
    12245 void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const
    +
    12246 {
    +
    12247  // TODO optimize
    +
    12248  VmaStatInfo stat;
    +
    12249  CalcAllocationStatInfo(stat);
    +
    12250 
    +
    12251  PrintDetailedMap_Begin(
    +
    12252  json,
    +
    12253  stat.unusedBytes,
    +
    12254  stat.allocationCount,
    +
    12255  stat.unusedRangeCount);
    12256 
    -
    12257 bool VmaBlockMetadata_Buddy::CreateAllocationRequest(
    -
    12258  uint32_t currentFrameIndex,
    -
    12259  uint32_t frameInUseCount,
    -
    12260  VkDeviceSize bufferImageGranularity,
    -
    12261  VkDeviceSize allocSize,
    -
    12262  VkDeviceSize allocAlignment,
    -
    12263  bool upperAddress,
    -
    12264  VmaSuballocationType allocType,
    -
    12265  bool canMakeOtherLost,
    -
    12266  uint32_t strategy,
    -
    12267  VmaAllocationRequest* pAllocationRequest)
    -
    12268 {
    -
    12269  VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm.");
    -
    12270 
    -
    12271  // Simple way to respect bufferImageGranularity. May be optimized some day.
    -
    12272  // Whenever it might be an OPTIMAL image...
    -
    12273  if(allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN ||
    -
    12274  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    -
    12275  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL)
    -
    12276  {
    -
    12277  allocAlignment = VMA_MAX(allocAlignment, bufferImageGranularity);
    -
    12278  allocSize = VMA_MAX(allocSize, bufferImageGranularity);
    -
    12279  }
    -
    12280 
    -
    12281  if(allocSize > m_UsableSize)
    -
    12282  {
    -
    12283  return false;
    -
    12284  }
    +
    12257  PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0));
    +
    12258 
    +
    12259  const VkDeviceSize unusableSize = GetUnusableSize();
    +
    12260  if(unusableSize > 0)
    +
    12261  {
    +
    12262  PrintDetailedMap_UnusedRange(json,
    +
    12263  m_UsableSize, // offset
    +
    12264  unusableSize); // size
    +
    12265  }
    +
    12266 
    +
    12267  PrintDetailedMap_End(json);
    +
    12268 }
    +
    12269 
    +
    12270 #endif // #if VMA_STATS_STRING_ENABLED
    +
    12271 
    +
    12272 bool VmaBlockMetadata_Buddy::CreateAllocationRequest(
    +
    12273  uint32_t currentFrameIndex,
    +
    12274  uint32_t frameInUseCount,
    +
    12275  VkDeviceSize bufferImageGranularity,
    +
    12276  VkDeviceSize allocSize,
    +
    12277  VkDeviceSize allocAlignment,
    +
    12278  bool upperAddress,
    +
    12279  VmaSuballocationType allocType,
    +
    12280  bool canMakeOtherLost,
    +
    12281  uint32_t strategy,
    +
    12282  VmaAllocationRequest* pAllocationRequest)
    +
    12283 {
    +
    12284  VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm.");
    12285 
    -
    12286  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
    -
    12287  for(uint32_t level = targetLevel + 1; level--; )
    -
    12288  {
    -
    12289  for(Node* freeNode = m_FreeList[level].front;
    -
    12290  freeNode != VMA_NULL;
    -
    12291  freeNode = freeNode->free.next)
    -
    12292  {
    -
    12293  if(freeNode->offset % allocAlignment == 0)
    -
    12294  {
    -
    12295  pAllocationRequest->type = VmaAllocationRequestType::Normal;
    -
    12296  pAllocationRequest->offset = freeNode->offset;
    -
    12297  pAllocationRequest->sumFreeSize = LevelToNodeSize(level);
    -
    12298  pAllocationRequest->sumItemSize = 0;
    -
    12299  pAllocationRequest->itemsToMakeLostCount = 0;
    -
    12300  pAllocationRequest->customData = (void*)(uintptr_t)level;
    -
    12301  return true;
    -
    12302  }
    -
    12303  }
    -
    12304  }
    -
    12305 
    -
    12306  return false;
    -
    12307 }
    -
    12308 
    -
    12309 bool VmaBlockMetadata_Buddy::MakeRequestedAllocationsLost(
    -
    12310  uint32_t currentFrameIndex,
    -
    12311  uint32_t frameInUseCount,
    -
    12312  VmaAllocationRequest* pAllocationRequest)
    -
    12313 {
    -
    12314  /*
    -
    12315  Lost allocations are not supported in buddy allocator at the moment.
    -
    12316  Support might be added in the future.
    -
    12317  */
    -
    12318  return pAllocationRequest->itemsToMakeLostCount == 0;
    -
    12319 }
    +
    12286  // Simple way to respect bufferImageGranularity. May be optimized some day.
    +
    12287  // Whenever it might be an OPTIMAL image...
    +
    12288  if(allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN ||
    +
    12289  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    +
    12290  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL)
    +
    12291  {
    +
    12292  allocAlignment = VMA_MAX(allocAlignment, bufferImageGranularity);
    +
    12293  allocSize = VMA_MAX(allocSize, bufferImageGranularity);
    +
    12294  }
    +
    12295 
    +
    12296  if(allocSize > m_UsableSize)
    +
    12297  {
    +
    12298  return false;
    +
    12299  }
    +
    12300 
    +
    12301  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
    +
    12302  for(uint32_t level = targetLevel + 1; level--; )
    +
    12303  {
    +
    12304  for(Node* freeNode = m_FreeList[level].front;
    +
    12305  freeNode != VMA_NULL;
    +
    12306  freeNode = freeNode->free.next)
    +
    12307  {
    +
    12308  if(freeNode->offset % allocAlignment == 0)
    +
    12309  {
    +
    12310  pAllocationRequest->type = VmaAllocationRequestType::Normal;
    +
    12311  pAllocationRequest->offset = freeNode->offset;
    +
    12312  pAllocationRequest->sumFreeSize = LevelToNodeSize(level);
    +
    12313  pAllocationRequest->sumItemSize = 0;
    +
    12314  pAllocationRequest->itemsToMakeLostCount = 0;
    +
    12315  pAllocationRequest->customData = (void*)(uintptr_t)level;
    +
    12316  return true;
    +
    12317  }
    +
    12318  }
    +
    12319  }
    12320 
    -
    12321 uint32_t VmaBlockMetadata_Buddy::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    -
    12322 {
    -
    12323  /*
    -
    12324  Lost allocations are not supported in buddy allocator at the moment.
    -
    12325  Support might be added in the future.
    -
    12326  */
    -
    12327  return 0;
    -
    12328 }
    -
    12329 
    -
    12330 void VmaBlockMetadata_Buddy::Alloc(
    -
    12331  const VmaAllocationRequest& request,
    -
    12332  VmaSuballocationType type,
    -
    12333  VkDeviceSize allocSize,
    -
    12334  VmaAllocation hAllocation)
    -
    12335 {
    -
    12336  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
    -
    12337 
    -
    12338  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
    -
    12339  uint32_t currLevel = (uint32_t)(uintptr_t)request.customData;
    -
    12340 
    -
    12341  Node* currNode = m_FreeList[currLevel].front;
    -
    12342  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
    -
    12343  while(currNode->offset != request.offset)
    -
    12344  {
    -
    12345  currNode = currNode->free.next;
    -
    12346  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
    -
    12347  }
    -
    12348 
    -
    12349  // Go down, splitting free nodes.
    -
    12350  while(currLevel < targetLevel)
    -
    12351  {
    -
    12352  // currNode is already first free node at currLevel.
    -
    12353  // Remove it from list of free nodes at this currLevel.
    -
    12354  RemoveFromFreeList(currLevel, currNode);
    +
    12321  return false;
    +
    12322 }
    +
    12323 
    +
    12324 bool VmaBlockMetadata_Buddy::MakeRequestedAllocationsLost(
    +
    12325  uint32_t currentFrameIndex,
    +
    12326  uint32_t frameInUseCount,
    +
    12327  VmaAllocationRequest* pAllocationRequest)
    +
    12328 {
    +
    12329  /*
    +
    12330  Lost allocations are not supported in buddy allocator at the moment.
    +
    12331  Support might be added in the future.
    +
    12332  */
    +
    12333  return pAllocationRequest->itemsToMakeLostCount == 0;
    +
    12334 }
    +
    12335 
    +
    12336 uint32_t VmaBlockMetadata_Buddy::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
    +
    12337 {
    +
    12338  /*
    +
    12339  Lost allocations are not supported in buddy allocator at the moment.
    +
    12340  Support might be added in the future.
    +
    12341  */
    +
    12342  return 0;
    +
    12343 }
    +
    12344 
    +
    12345 void VmaBlockMetadata_Buddy::Alloc(
    +
    12346  const VmaAllocationRequest& request,
    +
    12347  VmaSuballocationType type,
    +
    12348  VkDeviceSize allocSize,
    +
    12349  VmaAllocation hAllocation)
    +
    12350 {
    +
    12351  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
    +
    12352 
    +
    12353  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
    +
    12354  uint32_t currLevel = (uint32_t)(uintptr_t)request.customData;
    12355 
    -
    12356  const uint32_t childrenLevel = currLevel + 1;
    -
    12357 
    -
    12358  // Create two free sub-nodes.
    -
    12359  Node* leftChild = vma_new(GetAllocationCallbacks(), Node)();
    -
    12360  Node* rightChild = vma_new(GetAllocationCallbacks(), Node)();
    -
    12361 
    -
    12362  leftChild->offset = currNode->offset;
    -
    12363  leftChild->type = Node::TYPE_FREE;
    -
    12364  leftChild->parent = currNode;
    -
    12365  leftChild->buddy = rightChild;
    -
    12366 
    -
    12367  rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel);
    -
    12368  rightChild->type = Node::TYPE_FREE;
    -
    12369  rightChild->parent = currNode;
    -
    12370  rightChild->buddy = leftChild;
    -
    12371 
    -
    12372  // Convert current currNode to split type.
    -
    12373  currNode->type = Node::TYPE_SPLIT;
    -
    12374  currNode->split.leftChild = leftChild;
    -
    12375 
    -
    12376  // Add child nodes to free list. Order is important!
    -
    12377  AddToFreeListFront(childrenLevel, rightChild);
    -
    12378  AddToFreeListFront(childrenLevel, leftChild);
    -
    12379 
    -
    12380  ++m_FreeCount;
    -
    12381  //m_SumFreeSize -= LevelToNodeSize(currLevel) % 2; // Useful only when level node sizes can be non power of 2.
    -
    12382  ++currLevel;
    -
    12383  currNode = m_FreeList[currLevel].front;
    -
    12384 
    -
    12385  /*
    -
    12386  We can be sure that currNode, as left child of node previously split,
    -
    12387  also fullfills the alignment requirement.
    -
    12388  */
    -
    12389  }
    +
    12356  Node* currNode = m_FreeList[currLevel].front;
    +
    12357  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
    +
    12358  while(currNode->offset != request.offset)
    +
    12359  {
    +
    12360  currNode = currNode->free.next;
    +
    12361  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
    +
    12362  }
    +
    12363 
    +
    12364  // Go down, splitting free nodes.
    +
    12365  while(currLevel < targetLevel)
    +
    12366  {
    +
    12367  // currNode is already first free node at currLevel.
    +
    12368  // Remove it from list of free nodes at this currLevel.
    +
    12369  RemoveFromFreeList(currLevel, currNode);
    +
    12370 
    +
    12371  const uint32_t childrenLevel = currLevel + 1;
    +
    12372 
    +
    12373  // Create two free sub-nodes.
    +
    12374  Node* leftChild = vma_new(GetAllocationCallbacks(), Node)();
    +
    12375  Node* rightChild = vma_new(GetAllocationCallbacks(), Node)();
    +
    12376 
    +
    12377  leftChild->offset = currNode->offset;
    +
    12378  leftChild->type = Node::TYPE_FREE;
    +
    12379  leftChild->parent = currNode;
    +
    12380  leftChild->buddy = rightChild;
    +
    12381 
    +
    12382  rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel);
    +
    12383  rightChild->type = Node::TYPE_FREE;
    +
    12384  rightChild->parent = currNode;
    +
    12385  rightChild->buddy = leftChild;
    +
    12386 
    +
    12387  // Convert current currNode to split type.
    +
    12388  currNode->type = Node::TYPE_SPLIT;
    +
    12389  currNode->split.leftChild = leftChild;
    12390 
    -
    12391  // Remove from free list.
    -
    12392  VMA_ASSERT(currLevel == targetLevel &&
    -
    12393  currNode != VMA_NULL &&
    -
    12394  currNode->type == Node::TYPE_FREE);
    -
    12395  RemoveFromFreeList(currLevel, currNode);
    -
    12396 
    -
    12397  // Convert to allocation node.
    -
    12398  currNode->type = Node::TYPE_ALLOCATION;
    -
    12399  currNode->allocation.alloc = hAllocation;
    -
    12400 
    -
    12401  ++m_AllocationCount;
    -
    12402  --m_FreeCount;
    -
    12403  m_SumFreeSize -= allocSize;
    -
    12404 }
    +
    12391  // Add child nodes to free list. Order is important!
    +
    12392  AddToFreeListFront(childrenLevel, rightChild);
    +
    12393  AddToFreeListFront(childrenLevel, leftChild);
    +
    12394 
    +
    12395  ++m_FreeCount;
    +
    12396  //m_SumFreeSize -= LevelToNodeSize(currLevel) % 2; // Useful only when level node sizes can be non power of 2.
    +
    12397  ++currLevel;
    +
    12398  currNode = m_FreeList[currLevel].front;
    +
    12399 
    +
    12400  /*
    +
    12401  We can be sure that currNode, as left child of node previously split,
    +
    12402  also fullfills the alignment requirement.
    +
    12403  */
    +
    12404  }
    12405 
    -
    12406 void VmaBlockMetadata_Buddy::DeleteNode(Node* node)
    -
    12407 {
    -
    12408  if(node->type == Node::TYPE_SPLIT)
    -
    12409  {
    -
    12410  DeleteNode(node->split.leftChild->buddy);
    -
    12411  DeleteNode(node->split.leftChild);
    -
    12412  }
    -
    12413 
    -
    12414  vma_delete(GetAllocationCallbacks(), node);
    -
    12415 }
    -
    12416 
    -
    12417 bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
    -
    12418 {
    -
    12419  VMA_VALIDATE(level < m_LevelCount);
    -
    12420  VMA_VALIDATE(curr->parent == parent);
    -
    12421  VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL));
    -
    12422  VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr);
    -
    12423  switch(curr->type)
    +
    12406  // Remove from free list.
    +
    12407  VMA_ASSERT(currLevel == targetLevel &&
    +
    12408  currNode != VMA_NULL &&
    +
    12409  currNode->type == Node::TYPE_FREE);
    +
    12410  RemoveFromFreeList(currLevel, currNode);
    +
    12411 
    +
    12412  // Convert to allocation node.
    +
    12413  currNode->type = Node::TYPE_ALLOCATION;
    +
    12414  currNode->allocation.alloc = hAllocation;
    +
    12415 
    +
    12416  ++m_AllocationCount;
    +
    12417  --m_FreeCount;
    +
    12418  m_SumFreeSize -= allocSize;
    +
    12419 }
    +
    12420 
    +
    12421 void VmaBlockMetadata_Buddy::DeleteNode(Node* node)
    +
    12422 {
    +
    12423  if(node->type == Node::TYPE_SPLIT)
    12424  {
    -
    12425  case Node::TYPE_FREE:
    -
    12426  // curr->free.prev, next are validated separately.
    -
    12427  ctx.calculatedSumFreeSize += levelNodeSize;
    -
    12428  ++ctx.calculatedFreeCount;
    -
    12429  break;
    -
    12430  case Node::TYPE_ALLOCATION:
    -
    12431  ++ctx.calculatedAllocationCount;
    -
    12432  ctx.calculatedSumFreeSize += levelNodeSize - curr->allocation.alloc->GetSize();
    -
    12433  VMA_VALIDATE(curr->allocation.alloc != VK_NULL_HANDLE);
    -
    12434  break;
    -
    12435  case Node::TYPE_SPLIT:
    -
    12436  {
    -
    12437  const uint32_t childrenLevel = level + 1;
    -
    12438  const VkDeviceSize childrenLevelNodeSize = levelNodeSize / 2;
    -
    12439  const Node* const leftChild = curr->split.leftChild;
    -
    12440  VMA_VALIDATE(leftChild != VMA_NULL);
    -
    12441  VMA_VALIDATE(leftChild->offset == curr->offset);
    -
    12442  if(!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize))
    -
    12443  {
    -
    12444  VMA_VALIDATE(false && "ValidateNode for left child failed.");
    -
    12445  }
    -
    12446  const Node* const rightChild = leftChild->buddy;
    -
    12447  VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize);
    -
    12448  if(!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize))
    -
    12449  {
    -
    12450  VMA_VALIDATE(false && "ValidateNode for right child failed.");
    -
    12451  }
    -
    12452  }
    -
    12453  break;
    -
    12454  default:
    -
    12455  return false;
    -
    12456  }
    -
    12457 
    -
    12458  return true;
    -
    12459 }
    -
    12460 
    -
    12461 uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const
    -
    12462 {
    -
    12463  // I know this could be optimized somehow e.g. by using std::log2p1 from C++20.
    -
    12464  uint32_t level = 0;
    -
    12465  VkDeviceSize currLevelNodeSize = m_UsableSize;
    -
    12466  VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1;
    -
    12467  while(allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount)
    -
    12468  {
    -
    12469  ++level;
    -
    12470  currLevelNodeSize = nextLevelNodeSize;
    -
    12471  nextLevelNodeSize = currLevelNodeSize >> 1;
    -
    12472  }
    -
    12473  return level;
    +
    12425  DeleteNode(node->split.leftChild->buddy);
    +
    12426  DeleteNode(node->split.leftChild);
    +
    12427  }
    +
    12428 
    +
    12429  vma_delete(GetAllocationCallbacks(), node);
    +
    12430 }
    +
    12431 
    +
    12432 bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
    +
    12433 {
    +
    12434  VMA_VALIDATE(level < m_LevelCount);
    +
    12435  VMA_VALIDATE(curr->parent == parent);
    +
    12436  VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL));
    +
    12437  VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr);
    +
    12438  switch(curr->type)
    +
    12439  {
    +
    12440  case Node::TYPE_FREE:
    +
    12441  // curr->free.prev, next are validated separately.
    +
    12442  ctx.calculatedSumFreeSize += levelNodeSize;
    +
    12443  ++ctx.calculatedFreeCount;
    +
    12444  break;
    +
    12445  case Node::TYPE_ALLOCATION:
    +
    12446  ++ctx.calculatedAllocationCount;
    +
    12447  ctx.calculatedSumFreeSize += levelNodeSize - curr->allocation.alloc->GetSize();
    +
    12448  VMA_VALIDATE(curr->allocation.alloc != VK_NULL_HANDLE);
    +
    12449  break;
    +
    12450  case Node::TYPE_SPLIT:
    +
    12451  {
    +
    12452  const uint32_t childrenLevel = level + 1;
    +
    12453  const VkDeviceSize childrenLevelNodeSize = levelNodeSize / 2;
    +
    12454  const Node* const leftChild = curr->split.leftChild;
    +
    12455  VMA_VALIDATE(leftChild != VMA_NULL);
    +
    12456  VMA_VALIDATE(leftChild->offset == curr->offset);
    +
    12457  if(!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize))
    +
    12458  {
    +
    12459  VMA_VALIDATE(false && "ValidateNode for left child failed.");
    +
    12460  }
    +
    12461  const Node* const rightChild = leftChild->buddy;
    +
    12462  VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize);
    +
    12463  if(!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize))
    +
    12464  {
    +
    12465  VMA_VALIDATE(false && "ValidateNode for right child failed.");
    +
    12466  }
    +
    12467  }
    +
    12468  break;
    +
    12469  default:
    +
    12470  return false;
    +
    12471  }
    +
    12472 
    +
    12473  return true;
    12474 }
    12475 
    -
    12476 void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset)
    -
    12477 {
    -
    12478  // Find node and level.
    -
    12479  Node* node = m_Root;
    -
    12480  VkDeviceSize nodeOffset = 0;
    -
    12481  uint32_t level = 0;
    -
    12482  VkDeviceSize levelNodeSize = LevelToNodeSize(0);
    -
    12483  while(node->type == Node::TYPE_SPLIT)
    -
    12484  {
    -
    12485  const VkDeviceSize nextLevelSize = levelNodeSize >> 1;
    -
    12486  if(offset < nodeOffset + nextLevelSize)
    -
    12487  {
    -
    12488  node = node->split.leftChild;
    -
    12489  }
    -
    12490  else
    -
    12491  {
    -
    12492  node = node->split.leftChild->buddy;
    -
    12493  nodeOffset += nextLevelSize;
    -
    12494  }
    -
    12495  ++level;
    -
    12496  levelNodeSize = nextLevelSize;
    -
    12497  }
    -
    12498 
    -
    12499  VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION);
    -
    12500  VMA_ASSERT(alloc == VK_NULL_HANDLE || node->allocation.alloc == alloc);
    -
    12501 
    -
    12502  ++m_FreeCount;
    -
    12503  --m_AllocationCount;
    -
    12504  m_SumFreeSize += alloc->GetSize();
    -
    12505 
    -
    12506  node->type = Node::TYPE_FREE;
    -
    12507 
    -
    12508  // Join free nodes if possible.
    -
    12509  while(level > 0 && node->buddy->type == Node::TYPE_FREE)
    -
    12510  {
    -
    12511  RemoveFromFreeList(level, node->buddy);
    -
    12512  Node* const parent = node->parent;
    +
    12476 uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const
    +
    12477 {
    +
    12478  // I know this could be optimized somehow e.g. by using std::log2p1 from C++20.
    +
    12479  uint32_t level = 0;
    +
    12480  VkDeviceSize currLevelNodeSize = m_UsableSize;
    +
    12481  VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1;
    +
    12482  while(allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount)
    +
    12483  {
    +
    12484  ++level;
    +
    12485  currLevelNodeSize = nextLevelNodeSize;
    +
    12486  nextLevelNodeSize = currLevelNodeSize >> 1;
    +
    12487  }
    +
    12488  return level;
    +
    12489 }
    +
    12490 
    +
    12491 void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset)
    +
    12492 {
    +
    12493  // Find node and level.
    +
    12494  Node* node = m_Root;
    +
    12495  VkDeviceSize nodeOffset = 0;
    +
    12496  uint32_t level = 0;
    +
    12497  VkDeviceSize levelNodeSize = LevelToNodeSize(0);
    +
    12498  while(node->type == Node::TYPE_SPLIT)
    +
    12499  {
    +
    12500  const VkDeviceSize nextLevelSize = levelNodeSize >> 1;
    +
    12501  if(offset < nodeOffset + nextLevelSize)
    +
    12502  {
    +
    12503  node = node->split.leftChild;
    +
    12504  }
    +
    12505  else
    +
    12506  {
    +
    12507  node = node->split.leftChild->buddy;
    +
    12508  nodeOffset += nextLevelSize;
    +
    12509  }
    +
    12510  ++level;
    +
    12511  levelNodeSize = nextLevelSize;
    +
    12512  }
    12513 
    -
    12514  vma_delete(GetAllocationCallbacks(), node->buddy);
    -
    12515  vma_delete(GetAllocationCallbacks(), node);
    -
    12516  parent->type = Node::TYPE_FREE;
    -
    12517 
    -
    12518  node = parent;
    -
    12519  --level;
    -
    12520  //m_SumFreeSize += LevelToNodeSize(level) % 2; // Useful only when level node sizes can be non power of 2.
    -
    12521  --m_FreeCount;
    -
    12522  }
    -
    12523 
    -
    12524  AddToFreeListFront(level, node);
    -
    12525 }
    -
    12526 
    -
    12527 void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const
    -
    12528 {
    -
    12529  switch(node->type)
    -
    12530  {
    -
    12531  case Node::TYPE_FREE:
    -
    12532  ++outInfo.unusedRangeCount;
    -
    12533  outInfo.unusedBytes += levelNodeSize;
    -
    12534  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);
    -
    12535  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, levelNodeSize);
    -
    12536  break;
    -
    12537  case Node::TYPE_ALLOCATION:
    -
    12538  {
    -
    12539  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
    -
    12540  ++outInfo.allocationCount;
    -
    12541  outInfo.usedBytes += allocSize;
    -
    12542  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, allocSize);
    -
    12543  outInfo.allocationSizeMin = VMA_MAX(outInfo.allocationSizeMin, allocSize);
    -
    12544 
    -
    12545  const VkDeviceSize unusedRangeSize = levelNodeSize - allocSize;
    -
    12546  if(unusedRangeSize > 0)
    -
    12547  {
    -
    12548  ++outInfo.unusedRangeCount;
    -
    12549  outInfo.unusedBytes += unusedRangeSize;
    -
    12550  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);
    -
    12551  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, unusedRangeSize);
    -
    12552  }
    -
    12553  }
    -
    12554  break;
    -
    12555  case Node::TYPE_SPLIT:
    -
    12556  {
    -
    12557  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
    -
    12558  const Node* const leftChild = node->split.leftChild;
    -
    12559  CalcAllocationStatInfoNode(outInfo, leftChild, childrenNodeSize);
    -
    12560  const Node* const rightChild = leftChild->buddy;
    -
    12561  CalcAllocationStatInfoNode(outInfo, rightChild, childrenNodeSize);
    -
    12562  }
    -
    12563  break;
    -
    12564  default:
    -
    12565  VMA_ASSERT(0);
    -
    12566  }
    -
    12567 }
    -
    12568 
    -
    12569 void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node)
    -
    12570 {
    -
    12571  VMA_ASSERT(node->type == Node::TYPE_FREE);
    -
    12572 
    -
    12573  // List is empty.
    -
    12574  Node* const frontNode = m_FreeList[level].front;
    -
    12575  if(frontNode == VMA_NULL)
    -
    12576  {
    -
    12577  VMA_ASSERT(m_FreeList[level].back == VMA_NULL);
    -
    12578  node->free.prev = node->free.next = VMA_NULL;
    -
    12579  m_FreeList[level].front = m_FreeList[level].back = node;
    -
    12580  }
    -
    12581  else
    -
    12582  {
    -
    12583  VMA_ASSERT(frontNode->free.prev == VMA_NULL);
    -
    12584  node->free.prev = VMA_NULL;
    -
    12585  node->free.next = frontNode;
    -
    12586  frontNode->free.prev = node;
    -
    12587  m_FreeList[level].front = node;
    -
    12588  }
    -
    12589 }
    -
    12590 
    -
    12591 void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node)
    -
    12592 {
    -
    12593  VMA_ASSERT(m_FreeList[level].front != VMA_NULL);
    -
    12594 
    -
    12595  // It is at the front.
    -
    12596  if(node->free.prev == VMA_NULL)
    +
    12514  VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION);
    +
    12515  VMA_ASSERT(alloc == VK_NULL_HANDLE || node->allocation.alloc == alloc);
    +
    12516 
    +
    12517  ++m_FreeCount;
    +
    12518  --m_AllocationCount;
    +
    12519  m_SumFreeSize += alloc->GetSize();
    +
    12520 
    +
    12521  node->type = Node::TYPE_FREE;
    +
    12522 
    +
    12523  // Join free nodes if possible.
    +
    12524  while(level > 0 && node->buddy->type == Node::TYPE_FREE)
    +
    12525  {
    +
    12526  RemoveFromFreeList(level, node->buddy);
    +
    12527  Node* const parent = node->parent;
    +
    12528 
    +
    12529  vma_delete(GetAllocationCallbacks(), node->buddy);
    +
    12530  vma_delete(GetAllocationCallbacks(), node);
    +
    12531  parent->type = Node::TYPE_FREE;
    +
    12532 
    +
    12533  node = parent;
    +
    12534  --level;
    +
    12535  //m_SumFreeSize += LevelToNodeSize(level) % 2; // Useful only when level node sizes can be non power of 2.
    +
    12536  --m_FreeCount;
    +
    12537  }
    +
    12538 
    +
    12539  AddToFreeListFront(level, node);
    +
    12540 }
    +
    12541 
    +
    12542 void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const
    +
    12543 {
    +
    12544  switch(node->type)
    +
    12545  {
    +
    12546  case Node::TYPE_FREE:
    +
    12547  ++outInfo.unusedRangeCount;
    +
    12548  outInfo.unusedBytes += levelNodeSize;
    +
    12549  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);
    +
    12550  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, levelNodeSize);
    +
    12551  break;
    +
    12552  case Node::TYPE_ALLOCATION:
    +
    12553  {
    +
    12554  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
    +
    12555  ++outInfo.allocationCount;
    +
    12556  outInfo.usedBytes += allocSize;
    +
    12557  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, allocSize);
    +
    12558  outInfo.allocationSizeMin = VMA_MAX(outInfo.allocationSizeMin, allocSize);
    +
    12559 
    +
    12560  const VkDeviceSize unusedRangeSize = levelNodeSize - allocSize;
    +
    12561  if(unusedRangeSize > 0)
    +
    12562  {
    +
    12563  ++outInfo.unusedRangeCount;
    +
    12564  outInfo.unusedBytes += unusedRangeSize;
    +
    12565  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);
    +
    12566  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, unusedRangeSize);
    +
    12567  }
    +
    12568  }
    +
    12569  break;
    +
    12570  case Node::TYPE_SPLIT:
    +
    12571  {
    +
    12572  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
    +
    12573  const Node* const leftChild = node->split.leftChild;
    +
    12574  CalcAllocationStatInfoNode(outInfo, leftChild, childrenNodeSize);
    +
    12575  const Node* const rightChild = leftChild->buddy;
    +
    12576  CalcAllocationStatInfoNode(outInfo, rightChild, childrenNodeSize);
    +
    12577  }
    +
    12578  break;
    +
    12579  default:
    +
    12580  VMA_ASSERT(0);
    +
    12581  }
    +
    12582 }
    +
    12583 
    +
    12584 void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node)
    +
    12585 {
    +
    12586  VMA_ASSERT(node->type == Node::TYPE_FREE);
    +
    12587 
    +
    12588  // List is empty.
    +
    12589  Node* const frontNode = m_FreeList[level].front;
    +
    12590  if(frontNode == VMA_NULL)
    +
    12591  {
    +
    12592  VMA_ASSERT(m_FreeList[level].back == VMA_NULL);
    +
    12593  node->free.prev = node->free.next = VMA_NULL;
    +
    12594  m_FreeList[level].front = m_FreeList[level].back = node;
    +
    12595  }
    +
    12596  else
    12597  {
    -
    12598  VMA_ASSERT(m_FreeList[level].front == node);
    -
    12599  m_FreeList[level].front = node->free.next;
    -
    12600  }
    -
    12601  else
    -
    12602  {
    -
    12603  Node* const prevFreeNode = node->free.prev;
    -
    12604  VMA_ASSERT(prevFreeNode->free.next == node);
    -
    12605  prevFreeNode->free.next = node->free.next;
    -
    12606  }
    -
    12607 
    -
    12608  // It is at the back.
    -
    12609  if(node->free.next == VMA_NULL)
    -
    12610  {
    -
    12611  VMA_ASSERT(m_FreeList[level].back == node);
    -
    12612  m_FreeList[level].back = node->free.prev;
    -
    12613  }
    -
    12614  else
    -
    12615  {
    -
    12616  Node* const nextFreeNode = node->free.next;
    -
    12617  VMA_ASSERT(nextFreeNode->free.prev == node);
    -
    12618  nextFreeNode->free.prev = node->free.prev;
    -
    12619  }
    -
    12620 }
    -
    12621 
    -
    12622 #if VMA_STATS_STRING_ENABLED
    -
    12623 void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const
    -
    12624 {
    -
    12625  switch(node->type)
    -
    12626  {
    -
    12627  case Node::TYPE_FREE:
    -
    12628  PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize);
    -
    12629  break;
    -
    12630  case Node::TYPE_ALLOCATION:
    -
    12631  {
    -
    12632  PrintDetailedMap_Allocation(json, node->offset, node->allocation.alloc);
    -
    12633  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
    -
    12634  if(allocSize < levelNodeSize)
    -
    12635  {
    -
    12636  PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize);
    -
    12637  }
    -
    12638  }
    -
    12639  break;
    -
    12640  case Node::TYPE_SPLIT:
    -
    12641  {
    -
    12642  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
    -
    12643  const Node* const leftChild = node->split.leftChild;
    -
    12644  PrintDetailedMapNode(json, leftChild, childrenNodeSize);
    -
    12645  const Node* const rightChild = leftChild->buddy;
    -
    12646  PrintDetailedMapNode(json, rightChild, childrenNodeSize);
    -
    12647  }
    -
    12648  break;
    -
    12649  default:
    -
    12650  VMA_ASSERT(0);
    -
    12651  }
    -
    12652 }
    -
    12653 #endif // #if VMA_STATS_STRING_ENABLED
    -
    12654 
    -
    12655 
    -
    12657 // class VmaDeviceMemoryBlock
    -
    12658 
    -
    12659 VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :
    -
    12660  m_pMetadata(VMA_NULL),
    -
    12661  m_MemoryTypeIndex(UINT32_MAX),
    -
    12662  m_Id(0),
    -
    12663  m_hMemory(VK_NULL_HANDLE),
    -
    12664  m_MapCount(0),
    -
    12665  m_pMappedData(VMA_NULL)
    -
    12666 {
    +
    12598  VMA_ASSERT(frontNode->free.prev == VMA_NULL);
    +
    12599  node->free.prev = VMA_NULL;
    +
    12600  node->free.next = frontNode;
    +
    12601  frontNode->free.prev = node;
    +
    12602  m_FreeList[level].front = node;
    +
    12603  }
    +
    12604 }
    +
    12605 
    +
    12606 void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node)
    +
    12607 {
    +
    12608  VMA_ASSERT(m_FreeList[level].front != VMA_NULL);
    +
    12609 
    +
    12610  // It is at the front.
    +
    12611  if(node->free.prev == VMA_NULL)
    +
    12612  {
    +
    12613  VMA_ASSERT(m_FreeList[level].front == node);
    +
    12614  m_FreeList[level].front = node->free.next;
    +
    12615  }
    +
    12616  else
    +
    12617  {
    +
    12618  Node* const prevFreeNode = node->free.prev;
    +
    12619  VMA_ASSERT(prevFreeNode->free.next == node);
    +
    12620  prevFreeNode->free.next = node->free.next;
    +
    12621  }
    +
    12622 
    +
    12623  // It is at the back.
    +
    12624  if(node->free.next == VMA_NULL)
    +
    12625  {
    +
    12626  VMA_ASSERT(m_FreeList[level].back == node);
    +
    12627  m_FreeList[level].back = node->free.prev;
    +
    12628  }
    +
    12629  else
    +
    12630  {
    +
    12631  Node* const nextFreeNode = node->free.next;
    +
    12632  VMA_ASSERT(nextFreeNode->free.prev == node);
    +
    12633  nextFreeNode->free.prev = node->free.prev;
    +
    12634  }
    +
    12635 }
    +
    12636 
    +
    12637 #if VMA_STATS_STRING_ENABLED
    +
    12638 void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const
    +
    12639 {
    +
    12640  switch(node->type)
    +
    12641  {
    +
    12642  case Node::TYPE_FREE:
    +
    12643  PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize);
    +
    12644  break;
    +
    12645  case Node::TYPE_ALLOCATION:
    +
    12646  {
    +
    12647  PrintDetailedMap_Allocation(json, node->offset, node->allocation.alloc);
    +
    12648  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
    +
    12649  if(allocSize < levelNodeSize)
    +
    12650  {
    +
    12651  PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize);
    +
    12652  }
    +
    12653  }
    +
    12654  break;
    +
    12655  case Node::TYPE_SPLIT:
    +
    12656  {
    +
    12657  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
    +
    12658  const Node* const leftChild = node->split.leftChild;
    +
    12659  PrintDetailedMapNode(json, leftChild, childrenNodeSize);
    +
    12660  const Node* const rightChild = leftChild->buddy;
    +
    12661  PrintDetailedMapNode(json, rightChild, childrenNodeSize);
    +
    12662  }
    +
    12663  break;
    +
    12664  default:
    +
    12665  VMA_ASSERT(0);
    +
    12666  }
    12667 }
    -
    12668 
    -
    12669 void VmaDeviceMemoryBlock::Init(
    -
    12670  VmaAllocator hAllocator,
    -
    12671  VmaPool hParentPool,
    -
    12672  uint32_t newMemoryTypeIndex,
    -
    12673  VkDeviceMemory newMemory,
    -
    12674  VkDeviceSize newSize,
    -
    12675  uint32_t id,
    -
    12676  uint32_t algorithm)
    -
    12677 {
    -
    12678  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    -
    12679 
    -
    12680  m_hParentPool = hParentPool;
    -
    12681  m_MemoryTypeIndex = newMemoryTypeIndex;
    -
    12682  m_Id = id;
    -
    12683  m_hMemory = newMemory;
    -
    12684 
    -
    12685  switch(algorithm)
    -
    12686  {
    -
    12687  case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT:
    -
    12688  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator);
    -
    12689  break;
    -
    12690  case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT:
    -
    12691  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Buddy)(hAllocator);
    -
    12692  break;
    -
    12693  default:
    -
    12694  VMA_ASSERT(0);
    -
    12695  // Fall-through.
    -
    12696  case 0:
    -
    12697  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Generic)(hAllocator);
    -
    12698  }
    -
    12699  m_pMetadata->Init(newSize);
    -
    12700 }
    -
    12701 
    -
    12702 void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
    -
    12703 {
    -
    12704  // This is the most important assert in the entire library.
    -
    12705  // Hitting it means you have some memory leak - unreleased VmaAllocation objects.
    -
    12706  VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
    -
    12707 
    -
    12708  VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
    -
    12709  allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory);
    -
    12710  m_hMemory = VK_NULL_HANDLE;
    -
    12711 
    -
    12712  vma_delete(allocator, m_pMetadata);
    -
    12713  m_pMetadata = VMA_NULL;
    -
    12714 }
    -
    12715 
    -
    12716 bool VmaDeviceMemoryBlock::Validate() const
    -
    12717 {
    -
    12718  VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) &&
    -
    12719  (m_pMetadata->GetSize() != 0));
    -
    12720 
    -
    12721  return m_pMetadata->Validate();
    -
    12722 }
    -
    12723 
    -
    12724 VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator)
    -
    12725 {
    -
    12726  void* pData = nullptr;
    -
    12727  VkResult res = Map(hAllocator, 1, &pData);
    -
    12728  if(res != VK_SUCCESS)
    -
    12729  {
    -
    12730  return res;
    -
    12731  }
    -
    12732 
    -
    12733  res = m_pMetadata->CheckCorruption(pData);
    -
    12734 
    -
    12735  Unmap(hAllocator, 1);
    -
    12736 
    -
    12737  return res;
    -
    12738 }
    -
    12739 
    -
    12740 VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData)
    -
    12741 {
    -
    12742  if(count == 0)
    -
    12743  {
    -
    12744  return VK_SUCCESS;
    -
    12745  }
    -
    12746 
    -
    12747  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    -
    12748  if(m_MapCount != 0)
    -
    12749  {
    -
    12750  m_MapCount += count;
    -
    12751  VMA_ASSERT(m_pMappedData != VMA_NULL);
    -
    12752  if(ppData != VMA_NULL)
    -
    12753  {
    -
    12754  *ppData = m_pMappedData;
    -
    12755  }
    -
    12756  return VK_SUCCESS;
    -
    12757  }
    -
    12758  else
    -
    12759  {
    -
    12760  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
    -
    12761  hAllocator->m_hDevice,
    -
    12762  m_hMemory,
    -
    12763  0, // offset
    -
    12764  VK_WHOLE_SIZE,
    -
    12765  0, // flags
    -
    12766  &m_pMappedData);
    -
    12767  if(result == VK_SUCCESS)
    +
    12668 #endif // #if VMA_STATS_STRING_ENABLED
    +
    12669 
    +
    12670 
    +
    12672 // class VmaDeviceMemoryBlock
    +
    12673 
    +
    12674 VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :
    +
    12675  m_pMetadata(VMA_NULL),
    +
    12676  m_MemoryTypeIndex(UINT32_MAX),
    +
    12677  m_Id(0),
    +
    12678  m_hMemory(VK_NULL_HANDLE),
    +
    12679  m_MapCount(0),
    +
    12680  m_pMappedData(VMA_NULL)
    +
    12681 {
    +
    12682 }
    +
    12683 
    +
    12684 void VmaDeviceMemoryBlock::Init(
    +
    12685  VmaAllocator hAllocator,
    +
    12686  VmaPool hParentPool,
    +
    12687  uint32_t newMemoryTypeIndex,
    +
    12688  VkDeviceMemory newMemory,
    +
    12689  VkDeviceSize newSize,
    +
    12690  uint32_t id,
    +
    12691  uint32_t algorithm)
    +
    12692 {
    +
    12693  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    +
    12694 
    +
    12695  m_hParentPool = hParentPool;
    +
    12696  m_MemoryTypeIndex = newMemoryTypeIndex;
    +
    12697  m_Id = id;
    +
    12698  m_hMemory = newMemory;
    +
    12699 
    +
    12700  switch(algorithm)
    +
    12701  {
    +
    12702  case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT:
    +
    12703  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator);
    +
    12704  break;
    +
    12705  case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT:
    +
    12706  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Buddy)(hAllocator);
    +
    12707  break;
    +
    12708  default:
    +
    12709  VMA_ASSERT(0);
    +
    12710  // Fall-through.
    +
    12711  case 0:
    +
    12712  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Generic)(hAllocator);
    +
    12713  }
    +
    12714  m_pMetadata->Init(newSize);
    +
    12715 }
    +
    12716 
    +
    12717 void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
    +
    12718 {
    +
    12719  // This is the most important assert in the entire library.
    +
    12720  // Hitting it means you have some memory leak - unreleased VmaAllocation objects.
    +
    12721  VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
    +
    12722 
    +
    12723  VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
    +
    12724  allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory);
    +
    12725  m_hMemory = VK_NULL_HANDLE;
    +
    12726 
    +
    12727  vma_delete(allocator, m_pMetadata);
    +
    12728  m_pMetadata = VMA_NULL;
    +
    12729 }
    +
    12730 
    +
    12731 bool VmaDeviceMemoryBlock::Validate() const
    +
    12732 {
    +
    12733  VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) &&
    +
    12734  (m_pMetadata->GetSize() != 0));
    +
    12735 
    +
    12736  return m_pMetadata->Validate();
    +
    12737 }
    +
    12738 
    +
    12739 VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator)
    +
    12740 {
    +
    12741  void* pData = nullptr;
    +
    12742  VkResult res = Map(hAllocator, 1, &pData);
    +
    12743  if(res != VK_SUCCESS)
    +
    12744  {
    +
    12745  return res;
    +
    12746  }
    +
    12747 
    +
    12748  res = m_pMetadata->CheckCorruption(pData);
    +
    12749 
    +
    12750  Unmap(hAllocator, 1);
    +
    12751 
    +
    12752  return res;
    +
    12753 }
    +
    12754 
    +
    12755 VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData)
    +
    12756 {
    +
    12757  if(count == 0)
    +
    12758  {
    +
    12759  return VK_SUCCESS;
    +
    12760  }
    +
    12761 
    +
    12762  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    +
    12763  if(m_MapCount != 0)
    +
    12764  {
    +
    12765  m_MapCount += count;
    +
    12766  VMA_ASSERT(m_pMappedData != VMA_NULL);
    +
    12767  if(ppData != VMA_NULL)
    12768  {
    -
    12769  if(ppData != VMA_NULL)
    -
    12770  {
    -
    12771  *ppData = m_pMappedData;
    -
    12772  }
    -
    12773  m_MapCount = count;
    -
    12774  }
    -
    12775  return result;
    -
    12776  }
    -
    12777 }
    -
    12778 
    -
    12779 void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count)
    -
    12780 {
    -
    12781  if(count == 0)
    -
    12782  {
    -
    12783  return;
    -
    12784  }
    -
    12785 
    -
    12786  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    -
    12787  if(m_MapCount >= count)
    -
    12788  {
    -
    12789  m_MapCount -= count;
    -
    12790  if(m_MapCount == 0)
    -
    12791  {
    -
    12792  m_pMappedData = VMA_NULL;
    -
    12793  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory);
    -
    12794  }
    -
    12795  }
    -
    12796  else
    +
    12769  *ppData = m_pMappedData;
    +
    12770  }
    +
    12771  return VK_SUCCESS;
    +
    12772  }
    +
    12773  else
    +
    12774  {
    +
    12775  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
    +
    12776  hAllocator->m_hDevice,
    +
    12777  m_hMemory,
    +
    12778  0, // offset
    +
    12779  VK_WHOLE_SIZE,
    +
    12780  0, // flags
    +
    12781  &m_pMappedData);
    +
    12782  if(result == VK_SUCCESS)
    +
    12783  {
    +
    12784  if(ppData != VMA_NULL)
    +
    12785  {
    +
    12786  *ppData = m_pMappedData;
    +
    12787  }
    +
    12788  m_MapCount = count;
    +
    12789  }
    +
    12790  return result;
    +
    12791  }
    +
    12792 }
    +
    12793 
    +
    12794 void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count)
    +
    12795 {
    +
    12796  if(count == 0)
    12797  {
    -
    12798  VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped.");
    +
    12798  return;
    12799  }
    -
    12800 }
    -
    12801 
    -
    12802 VkResult VmaDeviceMemoryBlock::WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
    -
    12803 {
    -
    12804  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
    -
    12805  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
    -
    12806 
    -
    12807  void* pData;
    -
    12808  VkResult res = Map(hAllocator, 1, &pData);
    -
    12809  if(res != VK_SUCCESS)
    -
    12810  {
    -
    12811  return res;
    -
    12812  }
    -
    12813 
    -
    12814  VmaWriteMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN);
    -
    12815  VmaWriteMagicValue(pData, allocOffset + allocSize);
    +
    12800 
    +
    12801  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    +
    12802  if(m_MapCount >= count)
    +
    12803  {
    +
    12804  m_MapCount -= count;
    +
    12805  if(m_MapCount == 0)
    +
    12806  {
    +
    12807  m_pMappedData = VMA_NULL;
    +
    12808  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory);
    +
    12809  }
    +
    12810  }
    +
    12811  else
    +
    12812  {
    +
    12813  VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped.");
    +
    12814  }
    +
    12815 }
    12816 
    -
    12817  Unmap(hAllocator, 1);
    -
    12818 
    -
    12819  return VK_SUCCESS;
    -
    12820 }
    +
    12817 VkResult VmaDeviceMemoryBlock::WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
    +
    12818 {
    +
    12819  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
    +
    12820  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
    12821 
    -
    12822 VkResult VmaDeviceMemoryBlock::ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
    -
    12823 {
    -
    12824  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
    -
    12825  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
    -
    12826 
    -
    12827  void* pData;
    -
    12828  VkResult res = Map(hAllocator, 1, &pData);
    -
    12829  if(res != VK_SUCCESS)
    -
    12830  {
    -
    12831  return res;
    -
    12832  }
    +
    12822  void* pData;
    +
    12823  VkResult res = Map(hAllocator, 1, &pData);
    +
    12824  if(res != VK_SUCCESS)
    +
    12825  {
    +
    12826  return res;
    +
    12827  }
    +
    12828 
    +
    12829  VmaWriteMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN);
    +
    12830  VmaWriteMagicValue(pData, allocOffset + allocSize);
    +
    12831 
    +
    12832  Unmap(hAllocator, 1);
    12833 
    -
    12834  if(!VmaValidateMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN))
    -
    12835  {
    -
    12836  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE FREED ALLOCATION!");
    -
    12837  }
    -
    12838  else if(!VmaValidateMagicValue(pData, allocOffset + allocSize))
    -
    12839  {
    -
    12840  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!");
    -
    12841  }
    -
    12842 
    -
    12843  Unmap(hAllocator, 1);
    -
    12844 
    -
    12845  return VK_SUCCESS;
    -
    12846 }
    -
    12847 
    -
    12848 VkResult VmaDeviceMemoryBlock::BindBufferMemory(
    -
    12849  const VmaAllocator hAllocator,
    -
    12850  const VmaAllocation hAllocation,
    -
    12851  VkDeviceSize allocationLocalOffset,
    -
    12852  VkBuffer hBuffer,
    -
    12853  const void* pNext)
    -
    12854 {
    -
    12855  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
    -
    12856  hAllocation->GetBlock() == this);
    -
    12857  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
    -
    12858  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
    -
    12859  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
    -
    12860  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
    -
    12861  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    -
    12862  return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext);
    -
    12863 }
    -
    12864 
    -
    12865 VkResult VmaDeviceMemoryBlock::BindImageMemory(
    -
    12866  const VmaAllocator hAllocator,
    -
    12867  const VmaAllocation hAllocation,
    -
    12868  VkDeviceSize allocationLocalOffset,
    -
    12869  VkImage hImage,
    -
    12870  const void* pNext)
    -
    12871 {
    -
    12872  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
    -
    12873  hAllocation->GetBlock() == this);
    -
    12874  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
    -
    12875  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
    -
    12876  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
    -
    12877  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
    -
    12878  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    -
    12879  return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
    -
    12880 }
    -
    12881 
    -
    12882 static void InitStatInfo(VmaStatInfo& outInfo)
    -
    12883 {
    -
    12884  memset(&outInfo, 0, sizeof(outInfo));
    -
    12885  outInfo.allocationSizeMin = UINT64_MAX;
    -
    12886  outInfo.unusedRangeSizeMin = UINT64_MAX;
    -
    12887 }
    -
    12888 
    -
    12889 // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
    -
    12890 static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
    -
    12891 {
    -
    12892  inoutInfo.blockCount += srcInfo.blockCount;
    -
    12893  inoutInfo.allocationCount += srcInfo.allocationCount;
    -
    12894  inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
    -
    12895  inoutInfo.usedBytes += srcInfo.usedBytes;
    -
    12896  inoutInfo.unusedBytes += srcInfo.unusedBytes;
    -
    12897  inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
    -
    12898  inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
    -
    12899  inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
    -
    12900  inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
    -
    12901 }
    -
    12902 
    -
    12903 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
    -
    12904 {
    -
    12905  inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
    -
    12906  VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
    -
    12907  inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
    -
    12908  VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
    -
    12909 }
    -
    12910 
    -
    12911 VmaPool_T::VmaPool_T(
    -
    12912  VmaAllocator hAllocator,
    -
    12913  const VmaPoolCreateInfo& createInfo,
    -
    12914  VkDeviceSize preferredBlockSize) :
    -
    12915  m_BlockVector(
    -
    12916  hAllocator,
    -
    12917  this, // hParentPool
    -
    12918  createInfo.memoryTypeIndex,
    -
    12919  createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize,
    -
    12920  createInfo.minBlockCount,
    -
    12921  createInfo.maxBlockCount,
    -
    12922  (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(),
    -
    12923  createInfo.frameInUseCount,
    -
    12924  createInfo.blockSize != 0, // explicitBlockSize
    -
    12925  createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm
    -
    12926  createInfo.priority,
    -
    12927  VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment),
    -
    12928  createInfo.pMemoryAllocateNext),
    -
    12929  m_Id(0),
    -
    12930  m_Name(VMA_NULL)
    -
    12931 {
    -
    12932 }
    -
    12933 
    -
    12934 VmaPool_T::~VmaPool_T()
    -
    12935 {
    -
    12936  VMA_ASSERT(m_PrevPool == VMA_NULL && m_NextPool == VMA_NULL);
    -
    12937 }
    -
    12938 
    -
    12939 void VmaPool_T::SetName(const char* pName)
    -
    12940 {
    -
    12941  const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks();
    -
    12942  VmaFreeString(allocs, m_Name);
    -
    12943 
    -
    12944  if(pName != VMA_NULL)
    -
    12945  {
    -
    12946  m_Name = VmaCreateStringCopy(allocs, pName);
    -
    12947  }
    -
    12948  else
    -
    12949  {
    -
    12950  m_Name = VMA_NULL;
    -
    12951  }
    +
    12834  return VK_SUCCESS;
    +
    12835 }
    +
    12836 
    +
    12837 VkResult VmaDeviceMemoryBlock::ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
    +
    12838 {
    +
    12839  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
    +
    12840  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
    +
    12841 
    +
    12842  void* pData;
    +
    12843  VkResult res = Map(hAllocator, 1, &pData);
    +
    12844  if(res != VK_SUCCESS)
    +
    12845  {
    +
    12846  return res;
    +
    12847  }
    +
    12848 
    +
    12849  if(!VmaValidateMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN))
    +
    12850  {
    +
    12851  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE FREED ALLOCATION!");
    +
    12852  }
    +
    12853  else if(!VmaValidateMagicValue(pData, allocOffset + allocSize))
    +
    12854  {
    +
    12855  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!");
    +
    12856  }
    +
    12857 
    +
    12858  Unmap(hAllocator, 1);
    +
    12859 
    +
    12860  return VK_SUCCESS;
    +
    12861 }
    +
    12862 
    +
    12863 VkResult VmaDeviceMemoryBlock::BindBufferMemory(
    +
    12864  const VmaAllocator hAllocator,
    +
    12865  const VmaAllocation hAllocation,
    +
    12866  VkDeviceSize allocationLocalOffset,
    +
    12867  VkBuffer hBuffer,
    +
    12868  const void* pNext)
    +
    12869 {
    +
    12870  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
    +
    12871  hAllocation->GetBlock() == this);
    +
    12872  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
    +
    12873  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
    +
    12874  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
    +
    12875  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
    +
    12876  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    +
    12877  return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext);
    +
    12878 }
    +
    12879 
    +
    12880 VkResult VmaDeviceMemoryBlock::BindImageMemory(
    +
    12881  const VmaAllocator hAllocator,
    +
    12882  const VmaAllocation hAllocation,
    +
    12883  VkDeviceSize allocationLocalOffset,
    +
    12884  VkImage hImage,
    +
    12885  const void* pNext)
    +
    12886 {
    +
    12887  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
    +
    12888  hAllocation->GetBlock() == this);
    +
    12889  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
    +
    12890  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
    +
    12891  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
    +
    12892  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
    +
    12893  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
    +
    12894  return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
    +
    12895 }
    +
    12896 
    +
    12897 static void InitStatInfo(VmaStatInfo& outInfo)
    +
    12898 {
    +
    12899  memset(&outInfo, 0, sizeof(outInfo));
    +
    12900  outInfo.allocationSizeMin = UINT64_MAX;
    +
    12901  outInfo.unusedRangeSizeMin = UINT64_MAX;
    +
    12902 }
    +
    12903 
    +
    12904 // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
    +
    12905 static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
    +
    12906 {
    +
    12907  inoutInfo.blockCount += srcInfo.blockCount;
    +
    12908  inoutInfo.allocationCount += srcInfo.allocationCount;
    +
    12909  inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
    +
    12910  inoutInfo.usedBytes += srcInfo.usedBytes;
    +
    12911  inoutInfo.unusedBytes += srcInfo.unusedBytes;
    +
    12912  inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
    +
    12913  inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
    +
    12914  inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
    +
    12915  inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
    +
    12916 }
    +
    12917 
    +
    12918 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
    +
    12919 {
    +
    12920  inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
    +
    12921  VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
    +
    12922  inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
    +
    12923  VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
    +
    12924 }
    +
    12925 
    +
    12926 VmaPool_T::VmaPool_T(
    +
    12927  VmaAllocator hAllocator,
    +
    12928  const VmaPoolCreateInfo& createInfo,
    +
    12929  VkDeviceSize preferredBlockSize) :
    +
    12930  m_BlockVector(
    +
    12931  hAllocator,
    +
    12932  this, // hParentPool
    +
    12933  createInfo.memoryTypeIndex,
    +
    12934  createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize,
    +
    12935  createInfo.minBlockCount,
    +
    12936  createInfo.maxBlockCount,
    +
    12937  (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(),
    +
    12938  createInfo.frameInUseCount,
    +
    12939  createInfo.blockSize != 0, // explicitBlockSize
    +
    12940  createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm
    +
    12941  createInfo.priority,
    +
    12942  VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment),
    +
    12943  createInfo.pMemoryAllocateNext),
    +
    12944  m_Id(0),
    +
    12945  m_Name(VMA_NULL)
    +
    12946 {
    +
    12947 }
    +
    12948 
    +
    12949 VmaPool_T::~VmaPool_T()
    +
    12950 {
    +
    12951  VMA_ASSERT(m_PrevPool == VMA_NULL && m_NextPool == VMA_NULL);
    12952 }
    12953 
    -
    12954 #if VMA_STATS_STRING_ENABLED
    -
    12955 
    -
    12956 #endif // #if VMA_STATS_STRING_ENABLED
    -
    12957 
    -
    12958 VmaBlockVector::VmaBlockVector(
    -
    12959  VmaAllocator hAllocator,
    -
    12960  VmaPool hParentPool,
    -
    12961  uint32_t memoryTypeIndex,
    -
    12962  VkDeviceSize preferredBlockSize,
    -
    12963  size_t minBlockCount,
    -
    12964  size_t maxBlockCount,
    -
    12965  VkDeviceSize bufferImageGranularity,
    -
    12966  uint32_t frameInUseCount,
    -
    12967  bool explicitBlockSize,
    -
    12968  uint32_t algorithm,
    -
    12969  float priority,
    -
    12970  VkDeviceSize minAllocationAlignment,
    -
    12971  void* pMemoryAllocateNext) :
    -
    12972  m_hAllocator(hAllocator),
    -
    12973  m_hParentPool(hParentPool),
    -
    12974  m_MemoryTypeIndex(memoryTypeIndex),
    -
    12975  m_PreferredBlockSize(preferredBlockSize),
    -
    12976  m_MinBlockCount(minBlockCount),
    -
    12977  m_MaxBlockCount(maxBlockCount),
    -
    12978  m_BufferImageGranularity(bufferImageGranularity),
    -
    12979  m_FrameInUseCount(frameInUseCount),
    -
    12980  m_ExplicitBlockSize(explicitBlockSize),
    -
    12981  m_Algorithm(algorithm),
    -
    12982  m_Priority(priority),
    -
    12983  m_MinAllocationAlignment(minAllocationAlignment),
    -
    12984  m_pMemoryAllocateNext(pMemoryAllocateNext),
    -
    12985  m_HasEmptyBlock(false),
    -
    12986  m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),
    -
    12987  m_NextBlockId(0)
    -
    12988 {
    -
    12989 }
    -
    12990 
    -
    12991 VmaBlockVector::~VmaBlockVector()
    -
    12992 {
    -
    12993  for(size_t i = m_Blocks.size(); i--; )
    -
    12994  {
    -
    12995  m_Blocks[i]->Destroy(m_hAllocator);
    -
    12996  vma_delete(m_hAllocator, m_Blocks[i]);
    -
    12997  }
    -
    12998 }
    -
    12999 
    -
    13000 VkResult VmaBlockVector::CreateMinBlocks()
    -
    13001 {
    -
    13002  for(size_t i = 0; i < m_MinBlockCount; ++i)
    -
    13003  {
    -
    13004  VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL);
    -
    13005  if(res != VK_SUCCESS)
    -
    13006  {
    -
    13007  return res;
    -
    13008  }
    -
    13009  }
    -
    13010  return VK_SUCCESS;
    -
    13011 }
    -
    13012 
    -
    13013 void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
    -
    13014 {
    -
    13015  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    13016 
    -
    13017  const size_t blockCount = m_Blocks.size();
    -
    13018 
    -
    13019  pStats->size = 0;
    -
    13020  pStats->unusedSize = 0;
    -
    13021  pStats->allocationCount = 0;
    -
    13022  pStats->unusedRangeCount = 0;
    -
    13023  pStats->unusedRangeSizeMax = 0;
    -
    13024  pStats->blockCount = blockCount;
    -
    13025 
    -
    13026  for(uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    -
    13027  {
    -
    13028  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    -
    13029  VMA_ASSERT(pBlock);
    -
    13030  VMA_HEAVY_ASSERT(pBlock->Validate());
    -
    13031  pBlock->m_pMetadata->AddPoolStats(*pStats);
    -
    13032  }
    -
    13033 }
    -
    13034 
    -
    13035 bool VmaBlockVector::IsEmpty()
    -
    13036 {
    -
    13037  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    13038  return m_Blocks.empty();
    -
    13039 }
    +
    12954 void VmaPool_T::SetName(const char* pName)
    +
    12955 {
    +
    12956  const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks();
    +
    12957  VmaFreeString(allocs, m_Name);
    +
    12958 
    +
    12959  if(pName != VMA_NULL)
    +
    12960  {
    +
    12961  m_Name = VmaCreateStringCopy(allocs, pName);
    +
    12962  }
    +
    12963  else
    +
    12964  {
    +
    12965  m_Name = VMA_NULL;
    +
    12966  }
    +
    12967 }
    +
    12968 
    +
    12969 #if VMA_STATS_STRING_ENABLED
    +
    12970 
    +
    12971 #endif // #if VMA_STATS_STRING_ENABLED
    +
    12972 
    +
    12973 VmaBlockVector::VmaBlockVector(
    +
    12974  VmaAllocator hAllocator,
    +
    12975  VmaPool hParentPool,
    +
    12976  uint32_t memoryTypeIndex,
    +
    12977  VkDeviceSize preferredBlockSize,
    +
    12978  size_t minBlockCount,
    +
    12979  size_t maxBlockCount,
    +
    12980  VkDeviceSize bufferImageGranularity,
    +
    12981  uint32_t frameInUseCount,
    +
    12982  bool explicitBlockSize,
    +
    12983  uint32_t algorithm,
    +
    12984  float priority,
    +
    12985  VkDeviceSize minAllocationAlignment,
    +
    12986  void* pMemoryAllocateNext) :
    +
    12987  m_hAllocator(hAllocator),
    +
    12988  m_hParentPool(hParentPool),
    +
    12989  m_MemoryTypeIndex(memoryTypeIndex),
    +
    12990  m_PreferredBlockSize(preferredBlockSize),
    +
    12991  m_MinBlockCount(minBlockCount),
    +
    12992  m_MaxBlockCount(maxBlockCount),
    +
    12993  m_BufferImageGranularity(bufferImageGranularity),
    +
    12994  m_FrameInUseCount(frameInUseCount),
    +
    12995  m_ExplicitBlockSize(explicitBlockSize),
    +
    12996  m_Algorithm(algorithm),
    +
    12997  m_Priority(priority),
    +
    12998  m_MinAllocationAlignment(minAllocationAlignment),
    +
    12999  m_pMemoryAllocateNext(pMemoryAllocateNext),
    +
    13000  m_HasEmptyBlock(false),
    +
    13001  m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),
    +
    13002  m_NextBlockId(0)
    +
    13003 {
    +
    13004 }
    +
    13005 
    +
    13006 VmaBlockVector::~VmaBlockVector()
    +
    13007 {
    +
    13008  for(size_t i = m_Blocks.size(); i--; )
    +
    13009  {
    +
    13010  m_Blocks[i]->Destroy(m_hAllocator);
    +
    13011  vma_delete(m_hAllocator, m_Blocks[i]);
    +
    13012  }
    +
    13013 }
    +
    13014 
    +
    13015 VkResult VmaBlockVector::CreateMinBlocks()
    +
    13016 {
    +
    13017  for(size_t i = 0; i < m_MinBlockCount; ++i)
    +
    13018  {
    +
    13019  VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL);
    +
    13020  if(res != VK_SUCCESS)
    +
    13021  {
    +
    13022  return res;
    +
    13023  }
    +
    13024  }
    +
    13025  return VK_SUCCESS;
    +
    13026 }
    +
    13027 
    +
    13028 void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
    +
    13029 {
    +
    13030  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    13031 
    +
    13032  const size_t blockCount = m_Blocks.size();
    +
    13033 
    +
    13034  pStats->size = 0;
    +
    13035  pStats->unusedSize = 0;
    +
    13036  pStats->allocationCount = 0;
    +
    13037  pStats->unusedRangeCount = 0;
    +
    13038  pStats->unusedRangeSizeMax = 0;
    +
    13039  pStats->blockCount = blockCount;
    13040 
    -
    13041 bool VmaBlockVector::IsCorruptionDetectionEnabled() const
    -
    13042 {
    -
    13043  const uint32_t requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    -
    13044  return (VMA_DEBUG_DETECT_CORRUPTION != 0) &&
    -
    13045  (VMA_DEBUG_MARGIN > 0) &&
    -
    13046  (m_Algorithm == 0 || m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) &&
    -
    13047  (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags;
    +
    13041  for(uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    +
    13042  {
    +
    13043  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    +
    13044  VMA_ASSERT(pBlock);
    +
    13045  VMA_HEAVY_ASSERT(pBlock->Validate());
    +
    13046  pBlock->m_pMetadata->AddPoolStats(*pStats);
    +
    13047  }
    13048 }
    13049 
    -
    13050 static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
    -
    13051 
    -
    13052 VkResult VmaBlockVector::Allocate(
    -
    13053  uint32_t currentFrameIndex,
    -
    13054  VkDeviceSize size,
    -
    13055  VkDeviceSize alignment,
    -
    13056  const VmaAllocationCreateInfo& createInfo,
    -
    13057  VmaSuballocationType suballocType,
    -
    13058  size_t allocationCount,
    -
    13059  VmaAllocation* pAllocations)
    -
    13060 {
    -
    13061  size_t allocIndex;
    -
    13062  VkResult res = VK_SUCCESS;
    -
    13063 
    -
    13064  alignment = VMA_MAX(alignment, m_MinAllocationAlignment);
    -
    13065 
    -
    13066  if(IsCorruptionDetectionEnabled())
    -
    13067  {
    -
    13068  size = VmaAlignUp<VkDeviceSize>(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
    -
    13069  alignment = VmaAlignUp<VkDeviceSize>(alignment, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
    -
    13070  }
    -
    13071 
    -
    13072  {
    -
    13073  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    13074  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    -
    13075  {
    -
    13076  res = AllocatePage(
    -
    13077  currentFrameIndex,
    -
    13078  size,
    -
    13079  alignment,
    -
    13080  createInfo,
    -
    13081  suballocType,
    -
    13082  pAllocations + allocIndex);
    -
    13083  if(res != VK_SUCCESS)
    -
    13084  {
    -
    13085  break;
    -
    13086  }
    -
    13087  }
    -
    13088  }
    -
    13089 
    -
    13090  if(res != VK_SUCCESS)
    -
    13091  {
    -
    13092  // Free all already created allocations.
    -
    13093  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
    -
    13094  while(allocIndex--)
    -
    13095  {
    -
    13096  VmaAllocation_T* const alloc = pAllocations[allocIndex];
    -
    13097  const VkDeviceSize allocSize = alloc->GetSize();
    -
    13098  Free(alloc);
    -
    13099  m_hAllocator->m_Budget.RemoveAllocation(heapIndex, allocSize);
    -
    13100  }
    -
    13101  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
    -
    13102  }
    -
    13103 
    -
    13104  return res;
    -
    13105 }
    -
    13106 
    -
    13107 VkResult VmaBlockVector::AllocatePage(
    -
    13108  uint32_t currentFrameIndex,
    -
    13109  VkDeviceSize size,
    -
    13110  VkDeviceSize alignment,
    -
    13111  const VmaAllocationCreateInfo& createInfo,
    -
    13112  VmaSuballocationType suballocType,
    -
    13113  VmaAllocation* pAllocation)
    -
    13114 {
    -
    13115  const bool isUpperAddress = (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
    -
    13116  bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0;
    -
    13117  const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
    -
    13118  const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
    -
    13119 
    -
    13120  VkDeviceSize freeMemory;
    -
    13121  {
    -
    13122  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
    -
    13123  VmaBudget heapBudget = {};
    -
    13124  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
    -
    13125  freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0;
    -
    13126  }
    -
    13127 
    -
    13128  const bool canFallbackToDedicated = !IsCustomPool();
    -
    13129  const bool canCreateNewBlock =
    -
    13130  ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
    -
    13131  (m_Blocks.size() < m_MaxBlockCount) &&
    -
    13132  (freeMemory >= size || !canFallbackToDedicated);
    -
    13133  uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;
    +
    13050 bool VmaBlockVector::IsEmpty()
    +
    13051 {
    +
    13052  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    13053  return m_Blocks.empty();
    +
    13054 }
    +
    13055 
    +
    13056 bool VmaBlockVector::IsCorruptionDetectionEnabled() const
    +
    13057 {
    +
    13058  const uint32_t requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    +
    13059  return (VMA_DEBUG_DETECT_CORRUPTION != 0) &&
    +
    13060  (VMA_DEBUG_MARGIN > 0) &&
    +
    13061  (m_Algorithm == 0 || m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) &&
    +
    13062  (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags;
    +
    13063 }
    +
    13064 
    +
    13065 static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
    +
    13066 
    +
    13067 VkResult VmaBlockVector::Allocate(
    +
    13068  uint32_t currentFrameIndex,
    +
    13069  VkDeviceSize size,
    +
    13070  VkDeviceSize alignment,
    +
    13071  const VmaAllocationCreateInfo& createInfo,
    +
    13072  VmaSuballocationType suballocType,
    +
    13073  size_t allocationCount,
    +
    13074  VmaAllocation* pAllocations)
    +
    13075 {
    +
    13076  size_t allocIndex;
    +
    13077  VkResult res = VK_SUCCESS;
    +
    13078 
    +
    13079  alignment = VMA_MAX(alignment, m_MinAllocationAlignment);
    +
    13080 
    +
    13081  if(IsCorruptionDetectionEnabled())
    +
    13082  {
    +
    13083  size = VmaAlignUp<VkDeviceSize>(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
    +
    13084  alignment = VmaAlignUp<VkDeviceSize>(alignment, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
    +
    13085  }
    +
    13086 
    +
    13087  {
    +
    13088  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    13089  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    +
    13090  {
    +
    13091  res = AllocatePage(
    +
    13092  currentFrameIndex,
    +
    13093  size,
    +
    13094  alignment,
    +
    13095  createInfo,
    +
    13096  suballocType,
    +
    13097  pAllocations + allocIndex);
    +
    13098  if(res != VK_SUCCESS)
    +
    13099  {
    +
    13100  break;
    +
    13101  }
    +
    13102  }
    +
    13103  }
    +
    13104 
    +
    13105  if(res != VK_SUCCESS)
    +
    13106  {
    +
    13107  // Free all already created allocations.
    +
    13108  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
    +
    13109  while(allocIndex--)
    +
    13110  {
    +
    13111  VmaAllocation_T* const alloc = pAllocations[allocIndex];
    +
    13112  const VkDeviceSize allocSize = alloc->GetSize();
    +
    13113  Free(alloc);
    +
    13114  m_hAllocator->m_Budget.RemoveAllocation(heapIndex, allocSize);
    +
    13115  }
    +
    13116  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
    +
    13117  }
    +
    13118 
    +
    13119  return res;
    +
    13120 }
    +
    13121 
    +
    13122 VkResult VmaBlockVector::AllocatePage(
    +
    13123  uint32_t currentFrameIndex,
    +
    13124  VkDeviceSize size,
    +
    13125  VkDeviceSize alignment,
    +
    13126  const VmaAllocationCreateInfo& createInfo,
    +
    13127  VmaSuballocationType suballocType,
    +
    13128  VmaAllocation* pAllocation)
    +
    13129 {
    +
    13130  const bool isUpperAddress = (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
    +
    13131  bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0;
    +
    13132  const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
    +
    13133  const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
    13134 
    -
    13135  // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.
    -
    13136  // Which in turn is available only when maxBlockCount = 1.
    -
    13137  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT && m_MaxBlockCount > 1)
    -
    13138  {
    -
    13139  canMakeOtherLost = false;
    -
    13140  }
    -
    13141 
    -
    13142  // Upper address can only be used with linear allocator and within single memory block.
    -
    13143  if(isUpperAddress &&
    -
    13144  (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1))
    -
    13145  {
    -
    13146  return VK_ERROR_FEATURE_NOT_PRESENT;
    -
    13147  }
    -
    13148 
    -
    13149  // Validate strategy.
    -
    13150  switch(strategy)
    -
    13151  {
    -
    13152  case 0:
    -
    13153  strategy = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT;
    -
    13154  break;
    -
    13155  case VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT:
    -
    13156  case VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT:
    -
    13157  case VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT:
    -
    13158  break;
    -
    13159  default:
    -
    13160  return VK_ERROR_FEATURE_NOT_PRESENT;
    -
    13161  }
    -
    13162 
    -
    13163  // Early reject: requested allocation size is larger that maximum block size for this block vector.
    -
    13164  if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize)
    -
    13165  {
    -
    13166  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    13167  }
    -
    13168 
    -
    13169  /*
    -
    13170  Under certain condition, this whole section can be skipped for optimization, so
    -
    13171  we move on directly to trying to allocate with canMakeOtherLost. That's the case
    -
    13172  e.g. for custom pools with linear algorithm.
    -
    13173  */
    -
    13174  if(!canMakeOtherLost || canCreateNewBlock)
    -
    13175  {
    -
    13176  // 1. Search existing allocations. Try to allocate without making other allocations lost.
    -
    13177  VmaAllocationCreateFlags allocFlagsCopy = createInfo.flags;
    -
    13178  allocFlagsCopy &= ~VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;
    -
    13179 
    -
    13180  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
    -
    13181  {
    -
    13182  // Use only last block.
    -
    13183  if(!m_Blocks.empty())
    -
    13184  {
    -
    13185  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back();
    -
    13186  VMA_ASSERT(pCurrBlock);
    -
    13187  VkResult res = AllocateFromBlock(
    -
    13188  pCurrBlock,
    -
    13189  currentFrameIndex,
    -
    13190  size,
    -
    13191  alignment,
    -
    13192  allocFlagsCopy,
    -
    13193  createInfo.pUserData,
    -
    13194  suballocType,
    -
    13195  strategy,
    -
    13196  pAllocation);
    -
    13197  if(res == VK_SUCCESS)
    -
    13198  {
    -
    13199  VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId());
    -
    13200  return VK_SUCCESS;
    -
    13201  }
    -
    13202  }
    -
    13203  }
    -
    13204  else
    -
    13205  {
    -
    13206  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)
    -
    13207  {
    -
    13208  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
    -
    13209  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
    -
    13210  {
    -
    13211  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    -
    13212  VMA_ASSERT(pCurrBlock);
    -
    13213  VkResult res = AllocateFromBlock(
    -
    13214  pCurrBlock,
    -
    13215  currentFrameIndex,
    -
    13216  size,
    -
    13217  alignment,
    -
    13218  allocFlagsCopy,
    -
    13219  createInfo.pUserData,
    -
    13220  suballocType,
    -
    13221  strategy,
    -
    13222  pAllocation);
    -
    13223  if(res == VK_SUCCESS)
    -
    13224  {
    -
    13225  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
    -
    13226  return VK_SUCCESS;
    -
    13227  }
    -
    13228  }
    -
    13229  }
    -
    13230  else // WORST_FIT, FIRST_FIT
    -
    13231  {
    -
    13232  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
    -
    13233  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
    -
    13234  {
    -
    13235  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    -
    13236  VMA_ASSERT(pCurrBlock);
    -
    13237  VkResult res = AllocateFromBlock(
    -
    13238  pCurrBlock,
    -
    13239  currentFrameIndex,
    -
    13240  size,
    -
    13241  alignment,
    -
    13242  allocFlagsCopy,
    -
    13243  createInfo.pUserData,
    -
    13244  suballocType,
    -
    13245  strategy,
    -
    13246  pAllocation);
    -
    13247  if(res == VK_SUCCESS)
    -
    13248  {
    -
    13249  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
    -
    13250  return VK_SUCCESS;
    -
    13251  }
    -
    13252  }
    -
    13253  }
    -
    13254  }
    -
    13255 
    -
    13256  // 2. Try to create new block.
    -
    13257  if(canCreateNewBlock)
    -
    13258  {
    -
    13259  // Calculate optimal size for new block.
    -
    13260  VkDeviceSize newBlockSize = m_PreferredBlockSize;
    -
    13261  uint32_t newBlockSizeShift = 0;
    -
    13262  const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
    -
    13263 
    -
    13264  if(!m_ExplicitBlockSize)
    -
    13265  {
    -
    13266  // Allocate 1/8, 1/4, 1/2 as first blocks.
    -
    13267  const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize();
    -
    13268  for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
    -
    13269  {
    -
    13270  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
    -
    13271  if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
    -
    13272  {
    -
    13273  newBlockSize = smallerNewBlockSize;
    -
    13274  ++newBlockSizeShift;
    -
    13275  }
    -
    13276  else
    -
    13277  {
    -
    13278  break;
    -
    13279  }
    -
    13280  }
    -
    13281  }
    -
    13282 
    -
    13283  size_t newBlockIndex = 0;
    -
    13284  VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
    -
    13285  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    13286  // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
    -
    13287  if(!m_ExplicitBlockSize)
    -
    13288  {
    -
    13289  while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
    -
    13290  {
    -
    13291  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
    -
    13292  if(smallerNewBlockSize >= size)
    -
    13293  {
    -
    13294  newBlockSize = smallerNewBlockSize;
    -
    13295  ++newBlockSizeShift;
    -
    13296  res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
    -
    13297  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    13298  }
    -
    13299  else
    -
    13300  {
    -
    13301  break;
    -
    13302  }
    -
    13303  }
    -
    13304  }
    -
    13305 
    -
    13306  if(res == VK_SUCCESS)
    -
    13307  {
    -
    13308  VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex];
    -
    13309  VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
    -
    13310 
    -
    13311  res = AllocateFromBlock(
    -
    13312  pBlock,
    -
    13313  currentFrameIndex,
    -
    13314  size,
    -
    13315  alignment,
    -
    13316  allocFlagsCopy,
    -
    13317  createInfo.pUserData,
    -
    13318  suballocType,
    -
    13319  strategy,
    -
    13320  pAllocation);
    -
    13321  if(res == VK_SUCCESS)
    -
    13322  {
    -
    13323  VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize);
    -
    13324  return VK_SUCCESS;
    -
    13325  }
    -
    13326  else
    -
    13327  {
    -
    13328  // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment.
    -
    13329  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    13330  }
    -
    13331  }
    -
    13332  }
    -
    13333  }
    -
    13334 
    -
    13335  // 3. Try to allocate from existing blocks with making other allocations lost.
    -
    13336  if(canMakeOtherLost)
    -
    13337  {
    -
    13338  uint32_t tryIndex = 0;
    -
    13339  for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex)
    -
    13340  {
    -
    13341  VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL;
    -
    13342  VmaAllocationRequest bestRequest = {};
    -
    13343  VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;
    -
    13344 
    -
    13345  // 1. Search existing allocations.
    -
    13346  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)
    -
    13347  {
    -
    13348  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
    -
    13349  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
    -
    13350  {
    -
    13351  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    -
    13352  VMA_ASSERT(pCurrBlock);
    -
    13353  VmaAllocationRequest currRequest = {};
    -
    13354  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
    -
    13355  currentFrameIndex,
    -
    13356  m_FrameInUseCount,
    -
    13357  m_BufferImageGranularity,
    -
    13358  size,
    -
    13359  alignment,
    -
    13360  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
    -
    13361  suballocType,
    -
    13362  canMakeOtherLost,
    -
    13363  strategy,
    -
    13364  &currRequest))
    -
    13365  {
    -
    13366  const VkDeviceSize currRequestCost = currRequest.CalcCost();
    -
    13367  if(pBestRequestBlock == VMA_NULL ||
    -
    13368  currRequestCost < bestRequestCost)
    -
    13369  {
    -
    13370  pBestRequestBlock = pCurrBlock;
    -
    13371  bestRequest = currRequest;
    -
    13372  bestRequestCost = currRequestCost;
    -
    13373 
    -
    13374  if(bestRequestCost == 0)
    -
    13375  {
    -
    13376  break;
    -
    13377  }
    -
    13378  }
    -
    13379  }
    -
    13380  }
    -
    13381  }
    -
    13382  else // WORST_FIT, FIRST_FIT
    -
    13383  {
    -
    13384  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
    -
    13385  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
    -
    13386  {
    -
    13387  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    -
    13388  VMA_ASSERT(pCurrBlock);
    -
    13389  VmaAllocationRequest currRequest = {};
    -
    13390  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
    -
    13391  currentFrameIndex,
    -
    13392  m_FrameInUseCount,
    -
    13393  m_BufferImageGranularity,
    -
    13394  size,
    -
    13395  alignment,
    -
    13396  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
    -
    13397  suballocType,
    -
    13398  canMakeOtherLost,
    -
    13399  strategy,
    -
    13400  &currRequest))
    -
    13401  {
    -
    13402  const VkDeviceSize currRequestCost = currRequest.CalcCost();
    -
    13403  if(pBestRequestBlock == VMA_NULL ||
    -
    13404  currRequestCost < bestRequestCost ||
    -
    13405  strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)
    -
    13406  {
    -
    13407  pBestRequestBlock = pCurrBlock;
    -
    13408  bestRequest = currRequest;
    -
    13409  bestRequestCost = currRequestCost;
    -
    13410 
    -
    13411  if(bestRequestCost == 0 ||
    -
    13412  strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)
    -
    13413  {
    -
    13414  break;
    -
    13415  }
    -
    13416  }
    -
    13417  }
    -
    13418  }
    -
    13419  }
    -
    13420 
    -
    13421  if(pBestRequestBlock != VMA_NULL)
    -
    13422  {
    -
    13423  if(mapped)
    -
    13424  {
    -
    13425  VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL);
    -
    13426  if(res != VK_SUCCESS)
    -
    13427  {
    -
    13428  return res;
    -
    13429  }
    -
    13430  }
    -
    13431 
    -
    13432  if(pBestRequestBlock->m_pMetadata->MakeRequestedAllocationsLost(
    -
    13433  currentFrameIndex,
    -
    13434  m_FrameInUseCount,
    -
    13435  &bestRequest))
    -
    13436  {
    -
    13437  // Allocate from this pBlock.
    -
    13438  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
    -
    13439  pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation);
    -
    13440  UpdateHasEmptyBlock();
    -
    13441  (*pAllocation)->InitBlockAllocation(
    -
    13442  pBestRequestBlock,
    -
    13443  bestRequest.offset,
    -
    13444  alignment,
    -
    13445  size,
    -
    13446  m_MemoryTypeIndex,
    -
    13447  suballocType,
    -
    13448  mapped,
    -
    13449  (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
    -
    13450  VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
    -
    13451  VMA_DEBUG_LOG(" Returned from existing block");
    -
    13452  (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
    -
    13453  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
    -
    13454  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    -
    13455  {
    -
    13456  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
    -
    13457  }
    -
    13458  if(IsCorruptionDetectionEnabled())
    -
    13459  {
    -
    13460  VkResult res = pBestRequestBlock->WriteMagicValueAroundAllocation(m_hAllocator, bestRequest.offset, size);
    -
    13461  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
    -
    13462  }
    -
    13463  return VK_SUCCESS;
    -
    13464  }
    -
    13465  // else: Some allocations must have been touched while we are here. Next try.
    -
    13466  }
    -
    13467  else
    -
    13468  {
    -
    13469  // Could not find place in any of the blocks - break outer loop.
    -
    13470  break;
    -
    13471  }
    -
    13472  }
    -
    13473  /* Maximum number of tries exceeded - a very unlike event when many other
    -
    13474  threads are simultaneously touching allocations making it impossible to make
    -
    13475  lost at the same time as we try to allocate. */
    -
    13476  if(tryIndex == VMA_ALLOCATION_TRY_COUNT)
    -
    13477  {
    -
    13478  return VK_ERROR_TOO_MANY_OBJECTS;
    -
    13479  }
    -
    13480  }
    -
    13481 
    -
    13482  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    13483 }
    -
    13484 
    -
    13485 void VmaBlockVector::Free(
    -
    13486  const VmaAllocation hAllocation)
    -
    13487 {
    -
    13488  VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
    -
    13489 
    -
    13490  bool budgetExceeded = false;
    -
    13491  {
    -
    13492  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
    -
    13493  VmaBudget heapBudget = {};
    -
    13494  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
    -
    13495  budgetExceeded = heapBudget.usage >= heapBudget.budget;
    -
    13496  }
    -
    13497 
    -
    13498  // Scope for lock.
    -
    13499  {
    -
    13500  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    13501 
    -
    13502  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
    -
    13503 
    -
    13504  if(IsCorruptionDetectionEnabled())
    -
    13505  {
    -
    13506  VkResult res = pBlock->ValidateMagicValueAroundAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize());
    -
    13507  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value.");
    -
    13508  }
    -
    13509 
    -
    13510  if(hAllocation->IsPersistentMap())
    -
    13511  {
    -
    13512  pBlock->Unmap(m_hAllocator, 1);
    -
    13513  }
    -
    13514 
    -
    13515  pBlock->m_pMetadata->Free(hAllocation);
    -
    13516  VMA_HEAVY_ASSERT(pBlock->Validate());
    -
    13517 
    -
    13518  VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex);
    -
    13519 
    -
    13520  const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount;
    -
    13521  // pBlock became empty after this deallocation.
    -
    13522  if(pBlock->m_pMetadata->IsEmpty())
    -
    13523  {
    -
    13524  // Already has empty block. We don't want to have two, so delete this one.
    -
    13525  if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock)
    -
    13526  {
    -
    13527  pBlockToDelete = pBlock;
    -
    13528  Remove(pBlock);
    -
    13529  }
    -
    13530  // else: We now have an empty block - leave it.
    -
    13531  }
    -
    13532  // pBlock didn't become empty, but we have another empty block - find and free that one.
    -
    13533  // (This is optional, heuristics.)
    -
    13534  else if(m_HasEmptyBlock && canDeleteBlock)
    -
    13535  {
    -
    13536  VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
    -
    13537  if(pLastBlock->m_pMetadata->IsEmpty())
    -
    13538  {
    -
    13539  pBlockToDelete = pLastBlock;
    -
    13540  m_Blocks.pop_back();
    -
    13541  }
    -
    13542  }
    -
    13543 
    -
    13544  UpdateHasEmptyBlock();
    -
    13545  IncrementallySortBlocks();
    -
    13546  }
    -
    13547 
    -
    13548  // Destruction of a free block. Deferred until this point, outside of mutex
    -
    13549  // lock, for performance reason.
    -
    13550  if(pBlockToDelete != VMA_NULL)
    -
    13551  {
    -
    13552  VMA_DEBUG_LOG(" Deleted empty block");
    -
    13553  pBlockToDelete->Destroy(m_hAllocator);
    -
    13554  vma_delete(m_hAllocator, pBlockToDelete);
    -
    13555  }
    -
    13556 }
    -
    13557 
    -
    13558 VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const
    -
    13559 {
    -
    13560  VkDeviceSize result = 0;
    -
    13561  for(size_t i = m_Blocks.size(); i--; )
    -
    13562  {
    -
    13563  result = VMA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
    -
    13564  if(result >= m_PreferredBlockSize)
    -
    13565  {
    -
    13566  break;
    -
    13567  }
    -
    13568  }
    -
    13569  return result;
    -
    13570 }
    -
    13571 
    -
    13572 void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock)
    -
    13573 {
    -
    13574  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    -
    13575  {
    -
    13576  if(m_Blocks[blockIndex] == pBlock)
    -
    13577  {
    -
    13578  VmaVectorRemove(m_Blocks, blockIndex);
    -
    13579  return;
    -
    13580  }
    -
    13581  }
    -
    13582  VMA_ASSERT(0);
    -
    13583 }
    -
    13584 
    -
    13585 void VmaBlockVector::IncrementallySortBlocks()
    -
    13586 {
    -
    13587  if(m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
    -
    13588  {
    -
    13589  // Bubble sort only until first swap.
    -
    13590  for(size_t i = 1; i < m_Blocks.size(); ++i)
    -
    13591  {
    -
    13592  if(m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
    -
    13593  {
    -
    13594  VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
    -
    13595  return;
    -
    13596  }
    -
    13597  }
    -
    13598  }
    -
    13599 }
    -
    13600 
    -
    13601 VkResult VmaBlockVector::AllocateFromBlock(
    -
    13602  VmaDeviceMemoryBlock* pBlock,
    -
    13603  uint32_t currentFrameIndex,
    -
    13604  VkDeviceSize size,
    -
    13605  VkDeviceSize alignment,
    -
    13606  VmaAllocationCreateFlags allocFlags,
    -
    13607  void* pUserData,
    -
    13608  VmaSuballocationType suballocType,
    -
    13609  uint32_t strategy,
    -
    13610  VmaAllocation* pAllocation)
    -
    13611 {
    -
    13612  VMA_ASSERT((allocFlags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) == 0);
    -
    13613  const bool isUpperAddress = (allocFlags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
    -
    13614  const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
    -
    13615  const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
    -
    13616 
    -
    13617  VmaAllocationRequest currRequest = {};
    -
    13618  if(pBlock->m_pMetadata->CreateAllocationRequest(
    -
    13619  currentFrameIndex,
    -
    13620  m_FrameInUseCount,
    -
    13621  m_BufferImageGranularity,
    -
    13622  size,
    -
    13623  alignment,
    -
    13624  isUpperAddress,
    -
    13625  suballocType,
    -
    13626  false, // canMakeOtherLost
    -
    13627  strategy,
    -
    13628  &currRequest))
    -
    13629  {
    -
    13630  // Allocate from pCurrBlock.
    -
    13631  VMA_ASSERT(currRequest.itemsToMakeLostCount == 0);
    -
    13632 
    -
    13633  if(mapped)
    -
    13634  {
    -
    13635  VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL);
    -
    13636  if(res != VK_SUCCESS)
    -
    13637  {
    -
    13638  return res;
    -
    13639  }
    -
    13640  }
    -
    13641 
    -
    13642  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
    -
    13643  pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation);
    -
    13644  UpdateHasEmptyBlock();
    -
    13645  (*pAllocation)->InitBlockAllocation(
    -
    13646  pBlock,
    -
    13647  currRequest.offset,
    -
    13648  alignment,
    -
    13649  size,
    -
    13650  m_MemoryTypeIndex,
    -
    13651  suballocType,
    -
    13652  mapped,
    -
    13653  (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
    -
    13654  VMA_HEAVY_ASSERT(pBlock->Validate());
    -
    13655  (*pAllocation)->SetUserData(m_hAllocator, pUserData);
    -
    13656  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
    -
    13657  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    -
    13658  {
    -
    13659  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
    -
    13660  }
    -
    13661  if(IsCorruptionDetectionEnabled())
    -
    13662  {
    -
    13663  VkResult res = pBlock->WriteMagicValueAroundAllocation(m_hAllocator, currRequest.offset, size);
    -
    13664  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
    -
    13665  }
    -
    13666  return VK_SUCCESS;
    -
    13667  }
    -
    13668  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    13669 }
    -
    13670 
    -
    13671 VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex)
    -
    13672 {
    -
    13673  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    -
    13674  allocInfo.pNext = m_pMemoryAllocateNext;
    -
    13675  allocInfo.memoryTypeIndex = m_MemoryTypeIndex;
    -
    13676  allocInfo.allocationSize = blockSize;
    -
    13677 
    -
    13678 #if VMA_BUFFER_DEVICE_ADDRESS
    -
    13679  // Every standalone block can potentially contain a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - always enable the feature.
    -
    13680  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
    -
    13681  if(m_hAllocator->m_UseKhrBufferDeviceAddress)
    -
    13682  {
    -
    13683  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
    -
    13684  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
    -
    13685  }
    -
    13686 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
    -
    13687 
    -
    13688 #if VMA_MEMORY_PRIORITY
    -
    13689  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
    -
    13690  if(m_hAllocator->m_UseExtMemoryPriority)
    -
    13691  {
    -
    13692  priorityInfo.priority = m_Priority;
    -
    13693  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
    -
    13694  }
    -
    13695 #endif // #if VMA_MEMORY_PRIORITY
    -
    13696 
    -
    13697 #if VMA_EXTERNAL_MEMORY
    -
    13698  // Attach VkExportMemoryAllocateInfoKHR if necessary.
    -
    13699  VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR };
    -
    13700  exportMemoryAllocInfo.handleTypes = m_hAllocator->GetExternalMemoryHandleTypeFlags(m_MemoryTypeIndex);
    -
    13701  if(exportMemoryAllocInfo.handleTypes != 0)
    -
    13702  {
    -
    13703  VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo);
    -
    13704  }
    -
    13705 #endif // #if VMA_EXTERNAL_MEMORY
    -
    13706 
    -
    13707  VkDeviceMemory mem = VK_NULL_HANDLE;
    -
    13708  VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem);
    -
    13709  if(res < 0)
    -
    13710  {
    -
    13711  return res;
    -
    13712  }
    -
    13713 
    -
    13714  // New VkDeviceMemory successfully created.
    -
    13715 
    -
    13716  // Create new Allocation for it.
    -
    13717  VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator);
    -
    13718  pBlock->Init(
    -
    13719  m_hAllocator,
    -
    13720  m_hParentPool,
    -
    13721  m_MemoryTypeIndex,
    -
    13722  mem,
    -
    13723  allocInfo.allocationSize,
    -
    13724  m_NextBlockId++,
    -
    13725  m_Algorithm);
    -
    13726 
    -
    13727  m_Blocks.push_back(pBlock);
    -
    13728  if(pNewBlockIndex != VMA_NULL)
    -
    13729  {
    -
    13730  *pNewBlockIndex = m_Blocks.size() - 1;
    -
    13731  }
    -
    13732 
    -
    13733  return VK_SUCCESS;
    -
    13734 }
    -
    13735 
    -
    13736 void VmaBlockVector::ApplyDefragmentationMovesCpu(
    -
    13737  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    -
    13738  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves)
    -
    13739 {
    -
    13740  const size_t blockCount = m_Blocks.size();
    -
    13741  const bool isNonCoherent = m_hAllocator->IsMemoryTypeNonCoherent(m_MemoryTypeIndex);
    -
    13742 
    -
    13743  enum BLOCK_FLAG
    +
    13135  VkDeviceSize freeMemory;
    +
    13136  {
    +
    13137  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
    +
    13138  VmaBudget heapBudget = {};
    +
    13139  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
    +
    13140  freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0;
    +
    13141  }
    +
    13142 
    +
    13143  const bool canFallbackToDedicated = !IsCustomPool();
    +
    13144  const bool canCreateNewBlock =
    +
    13145  ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
    +
    13146  (m_Blocks.size() < m_MaxBlockCount) &&
    +
    13147  (freeMemory >= size || !canFallbackToDedicated);
    +
    13148  uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;
    +
    13149 
    +
    13150  // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.
    +
    13151  // Which in turn is available only when maxBlockCount = 1.
    +
    13152  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT && m_MaxBlockCount > 1)
    +
    13153  {
    +
    13154  canMakeOtherLost = false;
    +
    13155  }
    +
    13156 
    +
    13157  // Upper address can only be used with linear allocator and within single memory block.
    +
    13158  if(isUpperAddress &&
    +
    13159  (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1))
    +
    13160  {
    +
    13161  return VK_ERROR_FEATURE_NOT_PRESENT;
    +
    13162  }
    +
    13163 
    +
    13164  // Validate strategy.
    +
    13165  switch(strategy)
    +
    13166  {
    +
    13167  case 0:
    +
    13168  strategy = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT;
    +
    13169  break;
    +
    13170  case VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT:
    +
    13171  case VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT:
    +
    13172  case VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT:
    +
    13173  break;
    +
    13174  default:
    +
    13175  return VK_ERROR_FEATURE_NOT_PRESENT;
    +
    13176  }
    +
    13177 
    +
    13178  // Early reject: requested allocation size is larger that maximum block size for this block vector.
    +
    13179  if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize)
    +
    13180  {
    +
    13181  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    13182  }
    +
    13183 
    +
    13184  /*
    +
    13185  Under certain condition, this whole section can be skipped for optimization, so
    +
    13186  we move on directly to trying to allocate with canMakeOtherLost. That's the case
    +
    13187  e.g. for custom pools with linear algorithm.
    +
    13188  */
    +
    13189  if(!canMakeOtherLost || canCreateNewBlock)
    +
    13190  {
    +
    13191  // 1. Search existing allocations. Try to allocate without making other allocations lost.
    +
    13192  VmaAllocationCreateFlags allocFlagsCopy = createInfo.flags;
    +
    13193  allocFlagsCopy &= ~VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;
    +
    13194 
    +
    13195  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
    +
    13196  {
    +
    13197  // Use only last block.
    +
    13198  if(!m_Blocks.empty())
    +
    13199  {
    +
    13200  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back();
    +
    13201  VMA_ASSERT(pCurrBlock);
    +
    13202  VkResult res = AllocateFromBlock(
    +
    13203  pCurrBlock,
    +
    13204  currentFrameIndex,
    +
    13205  size,
    +
    13206  alignment,
    +
    13207  allocFlagsCopy,
    +
    13208  createInfo.pUserData,
    +
    13209  suballocType,
    +
    13210  strategy,
    +
    13211  pAllocation);
    +
    13212  if(res == VK_SUCCESS)
    +
    13213  {
    +
    13214  VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId());
    +
    13215  return VK_SUCCESS;
    +
    13216  }
    +
    13217  }
    +
    13218  }
    +
    13219  else
    +
    13220  {
    +
    13221  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)
    +
    13222  {
    +
    13223  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
    +
    13224  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
    +
    13225  {
    +
    13226  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    +
    13227  VMA_ASSERT(pCurrBlock);
    +
    13228  VkResult res = AllocateFromBlock(
    +
    13229  pCurrBlock,
    +
    13230  currentFrameIndex,
    +
    13231  size,
    +
    13232  alignment,
    +
    13233  allocFlagsCopy,
    +
    13234  createInfo.pUserData,
    +
    13235  suballocType,
    +
    13236  strategy,
    +
    13237  pAllocation);
    +
    13238  if(res == VK_SUCCESS)
    +
    13239  {
    +
    13240  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
    +
    13241  return VK_SUCCESS;
    +
    13242  }
    +
    13243  }
    +
    13244  }
    +
    13245  else // WORST_FIT, FIRST_FIT
    +
    13246  {
    +
    13247  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
    +
    13248  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
    +
    13249  {
    +
    13250  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    +
    13251  VMA_ASSERT(pCurrBlock);
    +
    13252  VkResult res = AllocateFromBlock(
    +
    13253  pCurrBlock,
    +
    13254  currentFrameIndex,
    +
    13255  size,
    +
    13256  alignment,
    +
    13257  allocFlagsCopy,
    +
    13258  createInfo.pUserData,
    +
    13259  suballocType,
    +
    13260  strategy,
    +
    13261  pAllocation);
    +
    13262  if(res == VK_SUCCESS)
    +
    13263  {
    +
    13264  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
    +
    13265  return VK_SUCCESS;
    +
    13266  }
    +
    13267  }
    +
    13268  }
    +
    13269  }
    +
    13270 
    +
    13271  // 2. Try to create new block.
    +
    13272  if(canCreateNewBlock)
    +
    13273  {
    +
    13274  // Calculate optimal size for new block.
    +
    13275  VkDeviceSize newBlockSize = m_PreferredBlockSize;
    +
    13276  uint32_t newBlockSizeShift = 0;
    +
    13277  const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
    +
    13278 
    +
    13279  if(!m_ExplicitBlockSize)
    +
    13280  {
    +
    13281  // Allocate 1/8, 1/4, 1/2 as first blocks.
    +
    13282  const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize();
    +
    13283  for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
    +
    13284  {
    +
    13285  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
    +
    13286  if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
    +
    13287  {
    +
    13288  newBlockSize = smallerNewBlockSize;
    +
    13289  ++newBlockSizeShift;
    +
    13290  }
    +
    13291  else
    +
    13292  {
    +
    13293  break;
    +
    13294  }
    +
    13295  }
    +
    13296  }
    +
    13297 
    +
    13298  size_t newBlockIndex = 0;
    +
    13299  VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
    +
    13300  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    13301  // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
    +
    13302  if(!m_ExplicitBlockSize)
    +
    13303  {
    +
    13304  while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
    +
    13305  {
    +
    13306  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
    +
    13307  if(smallerNewBlockSize >= size)
    +
    13308  {
    +
    13309  newBlockSize = smallerNewBlockSize;
    +
    13310  ++newBlockSizeShift;
    +
    13311  res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
    +
    13312  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    13313  }
    +
    13314  else
    +
    13315  {
    +
    13316  break;
    +
    13317  }
    +
    13318  }
    +
    13319  }
    +
    13320 
    +
    13321  if(res == VK_SUCCESS)
    +
    13322  {
    +
    13323  VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex];
    +
    13324  VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
    +
    13325 
    +
    13326  res = AllocateFromBlock(
    +
    13327  pBlock,
    +
    13328  currentFrameIndex,
    +
    13329  size,
    +
    13330  alignment,
    +
    13331  allocFlagsCopy,
    +
    13332  createInfo.pUserData,
    +
    13333  suballocType,
    +
    13334  strategy,
    +
    13335  pAllocation);
    +
    13336  if(res == VK_SUCCESS)
    +
    13337  {
    +
    13338  VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize);
    +
    13339  return VK_SUCCESS;
    +
    13340  }
    +
    13341  else
    +
    13342  {
    +
    13343  // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment.
    +
    13344  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    13345  }
    +
    13346  }
    +
    13347  }
    +
    13348  }
    +
    13349 
    +
    13350  // 3. Try to allocate from existing blocks with making other allocations lost.
    +
    13351  if(canMakeOtherLost)
    +
    13352  {
    +
    13353  uint32_t tryIndex = 0;
    +
    13354  for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex)
    +
    13355  {
    +
    13356  VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL;
    +
    13357  VmaAllocationRequest bestRequest = {};
    +
    13358  VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;
    +
    13359 
    +
    13360  // 1. Search existing allocations.
    +
    13361  if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)
    +
    13362  {
    +
    13363  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
    +
    13364  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
    +
    13365  {
    +
    13366  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    +
    13367  VMA_ASSERT(pCurrBlock);
    +
    13368  VmaAllocationRequest currRequest = {};
    +
    13369  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
    +
    13370  currentFrameIndex,
    +
    13371  m_FrameInUseCount,
    +
    13372  m_BufferImageGranularity,
    +
    13373  size,
    +
    13374  alignment,
    +
    13375  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
    +
    13376  suballocType,
    +
    13377  canMakeOtherLost,
    +
    13378  strategy,
    +
    13379  &currRequest))
    +
    13380  {
    +
    13381  const VkDeviceSize currRequestCost = currRequest.CalcCost();
    +
    13382  if(pBestRequestBlock == VMA_NULL ||
    +
    13383  currRequestCost < bestRequestCost)
    +
    13384  {
    +
    13385  pBestRequestBlock = pCurrBlock;
    +
    13386  bestRequest = currRequest;
    +
    13387  bestRequestCost = currRequestCost;
    +
    13388 
    +
    13389  if(bestRequestCost == 0)
    +
    13390  {
    +
    13391  break;
    +
    13392  }
    +
    13393  }
    +
    13394  }
    +
    13395  }
    +
    13396  }
    +
    13397  else // WORST_FIT, FIRST_FIT
    +
    13398  {
    +
    13399  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
    +
    13400  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
    +
    13401  {
    +
    13402  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
    +
    13403  VMA_ASSERT(pCurrBlock);
    +
    13404  VmaAllocationRequest currRequest = {};
    +
    13405  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
    +
    13406  currentFrameIndex,
    +
    13407  m_FrameInUseCount,
    +
    13408  m_BufferImageGranularity,
    +
    13409  size,
    +
    13410  alignment,
    +
    13411  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
    +
    13412  suballocType,
    +
    13413  canMakeOtherLost,
    +
    13414  strategy,
    +
    13415  &currRequest))
    +
    13416  {
    +
    13417  const VkDeviceSize currRequestCost = currRequest.CalcCost();
    +
    13418  if(pBestRequestBlock == VMA_NULL ||
    +
    13419  currRequestCost < bestRequestCost ||
    +
    13420  strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)
    +
    13421  {
    +
    13422  pBestRequestBlock = pCurrBlock;
    +
    13423  bestRequest = currRequest;
    +
    13424  bestRequestCost = currRequestCost;
    +
    13425 
    +
    13426  if(bestRequestCost == 0 ||
    +
    13427  strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)
    +
    13428  {
    +
    13429  break;
    +
    13430  }
    +
    13431  }
    +
    13432  }
    +
    13433  }
    +
    13434  }
    +
    13435 
    +
    13436  if(pBestRequestBlock != VMA_NULL)
    +
    13437  {
    +
    13438  if(mapped)
    +
    13439  {
    +
    13440  VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL);
    +
    13441  if(res != VK_SUCCESS)
    +
    13442  {
    +
    13443  return res;
    +
    13444  }
    +
    13445  }
    +
    13446 
    +
    13447  if(pBestRequestBlock->m_pMetadata->MakeRequestedAllocationsLost(
    +
    13448  currentFrameIndex,
    +
    13449  m_FrameInUseCount,
    +
    13450  &bestRequest))
    +
    13451  {
    +
    13452  // Allocate from this pBlock.
    +
    13453  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
    +
    13454  pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation);
    +
    13455  UpdateHasEmptyBlock();
    +
    13456  (*pAllocation)->InitBlockAllocation(
    +
    13457  pBestRequestBlock,
    +
    13458  bestRequest.offset,
    +
    13459  alignment,
    +
    13460  size,
    +
    13461  m_MemoryTypeIndex,
    +
    13462  suballocType,
    +
    13463  mapped,
    +
    13464  (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
    +
    13465  VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
    +
    13466  VMA_DEBUG_LOG(" Returned from existing block");
    +
    13467  (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
    +
    13468  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
    +
    13469  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    +
    13470  {
    +
    13471  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
    +
    13472  }
    +
    13473  if(IsCorruptionDetectionEnabled())
    +
    13474  {
    +
    13475  VkResult res = pBestRequestBlock->WriteMagicValueAroundAllocation(m_hAllocator, bestRequest.offset, size);
    +
    13476  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
    +
    13477  }
    +
    13478  return VK_SUCCESS;
    +
    13479  }
    +
    13480  // else: Some allocations must have been touched while we are here. Next try.
    +
    13481  }
    +
    13482  else
    +
    13483  {
    +
    13484  // Could not find place in any of the blocks - break outer loop.
    +
    13485  break;
    +
    13486  }
    +
    13487  }
    +
    13488  /* Maximum number of tries exceeded - a very unlike event when many other
    +
    13489  threads are simultaneously touching allocations making it impossible to make
    +
    13490  lost at the same time as we try to allocate. */
    +
    13491  if(tryIndex == VMA_ALLOCATION_TRY_COUNT)
    +
    13492  {
    +
    13493  return VK_ERROR_TOO_MANY_OBJECTS;
    +
    13494  }
    +
    13495  }
    +
    13496 
    +
    13497  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    13498 }
    +
    13499 
    +
    13500 void VmaBlockVector::Free(
    +
    13501  const VmaAllocation hAllocation)
    +
    13502 {
    +
    13503  VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
    +
    13504 
    +
    13505  bool budgetExceeded = false;
    +
    13506  {
    +
    13507  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
    +
    13508  VmaBudget heapBudget = {};
    +
    13509  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
    +
    13510  budgetExceeded = heapBudget.usage >= heapBudget.budget;
    +
    13511  }
    +
    13512 
    +
    13513  // Scope for lock.
    +
    13514  {
    +
    13515  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    13516 
    +
    13517  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
    +
    13518 
    +
    13519  if(IsCorruptionDetectionEnabled())
    +
    13520  {
    +
    13521  VkResult res = pBlock->ValidateMagicValueAroundAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize());
    +
    13522  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value.");
    +
    13523  }
    +
    13524 
    +
    13525  if(hAllocation->IsPersistentMap())
    +
    13526  {
    +
    13527  pBlock->Unmap(m_hAllocator, 1);
    +
    13528  }
    +
    13529 
    +
    13530  pBlock->m_pMetadata->Free(hAllocation);
    +
    13531  VMA_HEAVY_ASSERT(pBlock->Validate());
    +
    13532 
    +
    13533  VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex);
    +
    13534 
    +
    13535  const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount;
    +
    13536  // pBlock became empty after this deallocation.
    +
    13537  if(pBlock->m_pMetadata->IsEmpty())
    +
    13538  {
    +
    13539  // Already has empty block. We don't want to have two, so delete this one.
    +
    13540  if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock)
    +
    13541  {
    +
    13542  pBlockToDelete = pBlock;
    +
    13543  Remove(pBlock);
    +
    13544  }
    +
    13545  // else: We now have an empty block - leave it.
    +
    13546  }
    +
    13547  // pBlock didn't become empty, but we have another empty block - find and free that one.
    +
    13548  // (This is optional, heuristics.)
    +
    13549  else if(m_HasEmptyBlock && canDeleteBlock)
    +
    13550  {
    +
    13551  VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
    +
    13552  if(pLastBlock->m_pMetadata->IsEmpty())
    +
    13553  {
    +
    13554  pBlockToDelete = pLastBlock;
    +
    13555  m_Blocks.pop_back();
    +
    13556  }
    +
    13557  }
    +
    13558 
    +
    13559  UpdateHasEmptyBlock();
    +
    13560  IncrementallySortBlocks();
    +
    13561  }
    +
    13562 
    +
    13563  // Destruction of a free block. Deferred until this point, outside of mutex
    +
    13564  // lock, for performance reason.
    +
    13565  if(pBlockToDelete != VMA_NULL)
    +
    13566  {
    +
    13567  VMA_DEBUG_LOG(" Deleted empty block");
    +
    13568  pBlockToDelete->Destroy(m_hAllocator);
    +
    13569  vma_delete(m_hAllocator, pBlockToDelete);
    +
    13570  }
    +
    13571 }
    +
    13572 
    +
    13573 VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const
    +
    13574 {
    +
    13575  VkDeviceSize result = 0;
    +
    13576  for(size_t i = m_Blocks.size(); i--; )
    +
    13577  {
    +
    13578  result = VMA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
    +
    13579  if(result >= m_PreferredBlockSize)
    +
    13580  {
    +
    13581  break;
    +
    13582  }
    +
    13583  }
    +
    13584  return result;
    +
    13585 }
    +
    13586 
    +
    13587 void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock)
    +
    13588 {
    +
    13589  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    +
    13590  {
    +
    13591  if(m_Blocks[blockIndex] == pBlock)
    +
    13592  {
    +
    13593  VmaVectorRemove(m_Blocks, blockIndex);
    +
    13594  return;
    +
    13595  }
    +
    13596  }
    +
    13597  VMA_ASSERT(0);
    +
    13598 }
    +
    13599 
    +
    13600 void VmaBlockVector::IncrementallySortBlocks()
    +
    13601 {
    +
    13602  if(m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
    +
    13603  {
    +
    13604  // Bubble sort only until first swap.
    +
    13605  for(size_t i = 1; i < m_Blocks.size(); ++i)
    +
    13606  {
    +
    13607  if(m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
    +
    13608  {
    +
    13609  VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
    +
    13610  return;
    +
    13611  }
    +
    13612  }
    +
    13613  }
    +
    13614 }
    +
    13615 
    +
    13616 VkResult VmaBlockVector::AllocateFromBlock(
    +
    13617  VmaDeviceMemoryBlock* pBlock,
    +
    13618  uint32_t currentFrameIndex,
    +
    13619  VkDeviceSize size,
    +
    13620  VkDeviceSize alignment,
    +
    13621  VmaAllocationCreateFlags allocFlags,
    +
    13622  void* pUserData,
    +
    13623  VmaSuballocationType suballocType,
    +
    13624  uint32_t strategy,
    +
    13625  VmaAllocation* pAllocation)
    +
    13626 {
    +
    13627  VMA_ASSERT((allocFlags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) == 0);
    +
    13628  const bool isUpperAddress = (allocFlags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
    +
    13629  const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
    +
    13630  const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
    +
    13631 
    +
    13632  VmaAllocationRequest currRequest = {};
    +
    13633  if(pBlock->m_pMetadata->CreateAllocationRequest(
    +
    13634  currentFrameIndex,
    +
    13635  m_FrameInUseCount,
    +
    13636  m_BufferImageGranularity,
    +
    13637  size,
    +
    13638  alignment,
    +
    13639  isUpperAddress,
    +
    13640  suballocType,
    +
    13641  false, // canMakeOtherLost
    +
    13642  strategy,
    +
    13643  &currRequest))
    +
    13644  {
    +
    13645  // Allocate from pCurrBlock.
    +
    13646  VMA_ASSERT(currRequest.itemsToMakeLostCount == 0);
    +
    13647 
    +
    13648  if(mapped)
    +
    13649  {
    +
    13650  VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL);
    +
    13651  if(res != VK_SUCCESS)
    +
    13652  {
    +
    13653  return res;
    +
    13654  }
    +
    13655  }
    +
    13656 
    +
    13657  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
    +
    13658  pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation);
    +
    13659  UpdateHasEmptyBlock();
    +
    13660  (*pAllocation)->InitBlockAllocation(
    +
    13661  pBlock,
    +
    13662  currRequest.offset,
    +
    13663  alignment,
    +
    13664  size,
    +
    13665  m_MemoryTypeIndex,
    +
    13666  suballocType,
    +
    13667  mapped,
    +
    13668  (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
    +
    13669  VMA_HEAVY_ASSERT(pBlock->Validate());
    +
    13670  (*pAllocation)->SetUserData(m_hAllocator, pUserData);
    +
    13671  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
    +
    13672  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    +
    13673  {
    +
    13674  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
    +
    13675  }
    +
    13676  if(IsCorruptionDetectionEnabled())
    +
    13677  {
    +
    13678  VkResult res = pBlock->WriteMagicValueAroundAllocation(m_hAllocator, currRequest.offset, size);
    +
    13679  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
    +
    13680  }
    +
    13681  return VK_SUCCESS;
    +
    13682  }
    +
    13683  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    13684 }
    +
    13685 
    +
    13686 VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex)
    +
    13687 {
    +
    13688  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    +
    13689  allocInfo.pNext = m_pMemoryAllocateNext;
    +
    13690  allocInfo.memoryTypeIndex = m_MemoryTypeIndex;
    +
    13691  allocInfo.allocationSize = blockSize;
    +
    13692 
    +
    13693 #if VMA_BUFFER_DEVICE_ADDRESS
    +
    13694  // Every standalone block can potentially contain a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - always enable the feature.
    +
    13695  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
    +
    13696  if(m_hAllocator->m_UseKhrBufferDeviceAddress)
    +
    13697  {
    +
    13698  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
    +
    13699  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
    +
    13700  }
    +
    13701 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
    +
    13702 
    +
    13703 #if VMA_MEMORY_PRIORITY
    +
    13704  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
    +
    13705  if(m_hAllocator->m_UseExtMemoryPriority)
    +
    13706  {
    +
    13707  priorityInfo.priority = m_Priority;
    +
    13708  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
    +
    13709  }
    +
    13710 #endif // #if VMA_MEMORY_PRIORITY
    +
    13711 
    +
    13712 #if VMA_EXTERNAL_MEMORY
    +
    13713  // Attach VkExportMemoryAllocateInfoKHR if necessary.
    +
    13714  VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR };
    +
    13715  exportMemoryAllocInfo.handleTypes = m_hAllocator->GetExternalMemoryHandleTypeFlags(m_MemoryTypeIndex);
    +
    13716  if(exportMemoryAllocInfo.handleTypes != 0)
    +
    13717  {
    +
    13718  VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo);
    +
    13719  }
    +
    13720 #endif // #if VMA_EXTERNAL_MEMORY
    +
    13721 
    +
    13722  VkDeviceMemory mem = VK_NULL_HANDLE;
    +
    13723  VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem);
    +
    13724  if(res < 0)
    +
    13725  {
    +
    13726  return res;
    +
    13727  }
    +
    13728 
    +
    13729  // New VkDeviceMemory successfully created.
    +
    13730 
    +
    13731  // Create new Allocation for it.
    +
    13732  VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator);
    +
    13733  pBlock->Init(
    +
    13734  m_hAllocator,
    +
    13735  m_hParentPool,
    +
    13736  m_MemoryTypeIndex,
    +
    13737  mem,
    +
    13738  allocInfo.allocationSize,
    +
    13739  m_NextBlockId++,
    +
    13740  m_Algorithm);
    +
    13741 
    +
    13742  m_Blocks.push_back(pBlock);
    +
    13743  if(pNewBlockIndex != VMA_NULL)
    13744  {
    -
    13745  BLOCK_FLAG_USED = 0x00000001,
    -
    13746  BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION = 0x00000002,
    -
    13747  };
    -
    13748 
    -
    13749  struct BlockInfo
    -
    13750  {
    -
    13751  uint32_t flags;
    -
    13752  void* pMappedData;
    -
    13753  };
    -
    13754  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> >
    -
    13755  blockInfo(blockCount, BlockInfo(), VmaStlAllocator<BlockInfo>(m_hAllocator->GetAllocationCallbacks()));
    -
    13756  memset(blockInfo.data(), 0, blockCount * sizeof(BlockInfo));
    +
    13745  *pNewBlockIndex = m_Blocks.size() - 1;
    +
    13746  }
    +
    13747 
    +
    13748  return VK_SUCCESS;
    +
    13749 }
    +
    13750 
    +
    13751 void VmaBlockVector::ApplyDefragmentationMovesCpu(
    +
    13752  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    +
    13753  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves)
    +
    13754 {
    +
    13755  const size_t blockCount = m_Blocks.size();
    +
    13756  const bool isNonCoherent = m_hAllocator->IsMemoryTypeNonCoherent(m_MemoryTypeIndex);
    13757 
    -
    13758  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
    -
    13759  const size_t moveCount = moves.size();
    -
    13760  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    -
    13761  {
    -
    13762  const VmaDefragmentationMove& move = moves[moveIndex];
    -
    13763  blockInfo[move.srcBlockIndex].flags |= BLOCK_FLAG_USED;
    -
    13764  blockInfo[move.dstBlockIndex].flags |= BLOCK_FLAG_USED;
    -
    13765  }
    -
    13766 
    -
    13767  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
    -
    13768 
    -
    13769  // Go over all blocks. Get mapped pointer or map if necessary.
    -
    13770  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
    -
    13771  {
    -
    13772  BlockInfo& currBlockInfo = blockInfo[blockIndex];
    -
    13773  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    -
    13774  if((currBlockInfo.flags & BLOCK_FLAG_USED) != 0)
    -
    13775  {
    -
    13776  currBlockInfo.pMappedData = pBlock->GetMappedData();
    -
    13777  // It is not originally mapped - map it.
    -
    13778  if(currBlockInfo.pMappedData == VMA_NULL)
    -
    13779  {
    -
    13780  pDefragCtx->res = pBlock->Map(m_hAllocator, 1, &currBlockInfo.pMappedData);
    -
    13781  if(pDefragCtx->res == VK_SUCCESS)
    -
    13782  {
    -
    13783  currBlockInfo.flags |= BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION;
    -
    13784  }
    -
    13785  }
    -
    13786  }
    -
    13787  }
    -
    13788 
    -
    13789  // Go over all moves. Do actual data transfer.
    -
    13790  if(pDefragCtx->res == VK_SUCCESS)
    -
    13791  {
    -
    13792  const VkDeviceSize nonCoherentAtomSize = m_hAllocator->m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
    -
    13793  VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
    -
    13794 
    -
    13795  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    -
    13796  {
    -
    13797  const VmaDefragmentationMove& move = moves[moveIndex];
    -
    13798 
    -
    13799  const BlockInfo& srcBlockInfo = blockInfo[move.srcBlockIndex];
    -
    13800  const BlockInfo& dstBlockInfo = blockInfo[move.dstBlockIndex];
    -
    13801 
    -
    13802  VMA_ASSERT(srcBlockInfo.pMappedData && dstBlockInfo.pMappedData);
    +
    13758  enum BLOCK_FLAG
    +
    13759  {
    +
    13760  BLOCK_FLAG_USED = 0x00000001,
    +
    13761  BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION = 0x00000002,
    +
    13762  };
    +
    13763 
    +
    13764  struct BlockInfo
    +
    13765  {
    +
    13766  uint32_t flags;
    +
    13767  void* pMappedData;
    +
    13768  };
    +
    13769  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> >
    +
    13770  blockInfo(blockCount, BlockInfo(), VmaStlAllocator<BlockInfo>(m_hAllocator->GetAllocationCallbacks()));
    +
    13771  memset(blockInfo.data(), 0, blockCount * sizeof(BlockInfo));
    +
    13772 
    +
    13773  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
    +
    13774  const size_t moveCount = moves.size();
    +
    13775  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    +
    13776  {
    +
    13777  const VmaDefragmentationMove& move = moves[moveIndex];
    +
    13778  blockInfo[move.srcBlockIndex].flags |= BLOCK_FLAG_USED;
    +
    13779  blockInfo[move.dstBlockIndex].flags |= BLOCK_FLAG_USED;
    +
    13780  }
    +
    13781 
    +
    13782  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
    +
    13783 
    +
    13784  // Go over all blocks. Get mapped pointer or map if necessary.
    +
    13785  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
    +
    13786  {
    +
    13787  BlockInfo& currBlockInfo = blockInfo[blockIndex];
    +
    13788  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    +
    13789  if((currBlockInfo.flags & BLOCK_FLAG_USED) != 0)
    +
    13790  {
    +
    13791  currBlockInfo.pMappedData = pBlock->GetMappedData();
    +
    13792  // It is not originally mapped - map it.
    +
    13793  if(currBlockInfo.pMappedData == VMA_NULL)
    +
    13794  {
    +
    13795  pDefragCtx->res = pBlock->Map(m_hAllocator, 1, &currBlockInfo.pMappedData);
    +
    13796  if(pDefragCtx->res == VK_SUCCESS)
    +
    13797  {
    +
    13798  currBlockInfo.flags |= BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION;
    +
    13799  }
    +
    13800  }
    +
    13801  }
    +
    13802  }
    13803 
    -
    13804  // Invalidate source.
    -
    13805  if(isNonCoherent)
    -
    13806  {
    -
    13807  VmaDeviceMemoryBlock* const pSrcBlock = m_Blocks[move.srcBlockIndex];
    -
    13808  memRange.memory = pSrcBlock->GetDeviceMemory();
    -
    13809  memRange.offset = VmaAlignDown(move.srcOffset, nonCoherentAtomSize);
    -
    13810  memRange.size = VMA_MIN(
    -
    13811  VmaAlignUp(move.size + (move.srcOffset - memRange.offset), nonCoherentAtomSize),
    -
    13812  pSrcBlock->m_pMetadata->GetSize() - memRange.offset);
    -
    13813  (*m_hAllocator->GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
    -
    13814  }
    -
    13815 
    -
    13816  // THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
    -
    13817  memmove(
    -
    13818  reinterpret_cast<char*>(dstBlockInfo.pMappedData) + move.dstOffset,
    -
    13819  reinterpret_cast<char*>(srcBlockInfo.pMappedData) + move.srcOffset,
    -
    13820  static_cast<size_t>(move.size));
    -
    13821 
    -
    13822  if(IsCorruptionDetectionEnabled())
    -
    13823  {
    -
    13824  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset - VMA_DEBUG_MARGIN);
    -
    13825  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset + move.size);
    -
    13826  }
    -
    13827 
    -
    13828  // Flush destination.
    -
    13829  if(isNonCoherent)
    -
    13830  {
    -
    13831  VmaDeviceMemoryBlock* const pDstBlock = m_Blocks[move.dstBlockIndex];
    -
    13832  memRange.memory = pDstBlock->GetDeviceMemory();
    -
    13833  memRange.offset = VmaAlignDown(move.dstOffset, nonCoherentAtomSize);
    -
    13834  memRange.size = VMA_MIN(
    -
    13835  VmaAlignUp(move.size + (move.dstOffset - memRange.offset), nonCoherentAtomSize),
    -
    13836  pDstBlock->m_pMetadata->GetSize() - memRange.offset);
    -
    13837  (*m_hAllocator->GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
    -
    13838  }
    -
    13839  }
    -
    13840  }
    -
    13841 
    -
    13842  // Go over all blocks in reverse order. Unmap those that were mapped just for defragmentation.
    -
    13843  // Regardless of pCtx->res == VK_SUCCESS.
    -
    13844  for(size_t blockIndex = blockCount; blockIndex--; )
    -
    13845  {
    -
    13846  const BlockInfo& currBlockInfo = blockInfo[blockIndex];
    -
    13847  if((currBlockInfo.flags & BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION) != 0)
    -
    13848  {
    -
    13849  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    -
    13850  pBlock->Unmap(m_hAllocator, 1);
    -
    13851  }
    -
    13852  }
    -
    13853 }
    -
    13854 
    -
    13855 void VmaBlockVector::ApplyDefragmentationMovesGpu(
    -
    13856  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    -
    13857  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    13858  VkCommandBuffer commandBuffer)
    -
    13859 {
    -
    13860  const size_t blockCount = m_Blocks.size();
    -
    13861 
    -
    13862  pDefragCtx->blockContexts.resize(blockCount);
    -
    13863  memset(pDefragCtx->blockContexts.data(), 0, blockCount * sizeof(VmaBlockDefragmentationContext));
    -
    13864 
    -
    13865  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
    -
    13866  const size_t moveCount = moves.size();
    -
    13867  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    -
    13868  {
    -
    13869  const VmaDefragmentationMove& move = moves[moveIndex];
    -
    13870 
    -
    13871  //if(move.type == VMA_ALLOCATION_TYPE_UNKNOWN)
    -
    13872  {
    -
    13873  // Old school move still require us to map the whole block
    -
    13874  pDefragCtx->blockContexts[move.srcBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
    -
    13875  pDefragCtx->blockContexts[move.dstBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
    -
    13876  }
    -
    13877  }
    -
    13878 
    -
    13879  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
    -
    13880 
    -
    13881  // Go over all blocks. Create and bind buffer for whole block if necessary.
    -
    13882  {
    -
    13883  VkBufferCreateInfo bufCreateInfo;
    -
    13884  VmaFillGpuDefragmentationBufferCreateInfo(bufCreateInfo);
    +
    13804  // Go over all moves. Do actual data transfer.
    +
    13805  if(pDefragCtx->res == VK_SUCCESS)
    +
    13806  {
    +
    13807  const VkDeviceSize nonCoherentAtomSize = m_hAllocator->m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
    +
    13808  VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
    +
    13809 
    +
    13810  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    +
    13811  {
    +
    13812  const VmaDefragmentationMove& move = moves[moveIndex];
    +
    13813 
    +
    13814  const BlockInfo& srcBlockInfo = blockInfo[move.srcBlockIndex];
    +
    13815  const BlockInfo& dstBlockInfo = blockInfo[move.dstBlockIndex];
    +
    13816 
    +
    13817  VMA_ASSERT(srcBlockInfo.pMappedData && dstBlockInfo.pMappedData);
    +
    13818 
    +
    13819  // Invalidate source.
    +
    13820  if(isNonCoherent)
    +
    13821  {
    +
    13822  VmaDeviceMemoryBlock* const pSrcBlock = m_Blocks[move.srcBlockIndex];
    +
    13823  memRange.memory = pSrcBlock->GetDeviceMemory();
    +
    13824  memRange.offset = VmaAlignDown(move.srcOffset, nonCoherentAtomSize);
    +
    13825  memRange.size = VMA_MIN(
    +
    13826  VmaAlignUp(move.size + (move.srcOffset - memRange.offset), nonCoherentAtomSize),
    +
    13827  pSrcBlock->m_pMetadata->GetSize() - memRange.offset);
    +
    13828  (*m_hAllocator->GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
    +
    13829  }
    +
    13830 
    +
    13831  // THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
    +
    13832  memmove(
    +
    13833  reinterpret_cast<char*>(dstBlockInfo.pMappedData) + move.dstOffset,
    +
    13834  reinterpret_cast<char*>(srcBlockInfo.pMappedData) + move.srcOffset,
    +
    13835  static_cast<size_t>(move.size));
    +
    13836 
    +
    13837  if(IsCorruptionDetectionEnabled())
    +
    13838  {
    +
    13839  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset - VMA_DEBUG_MARGIN);
    +
    13840  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset + move.size);
    +
    13841  }
    +
    13842 
    +
    13843  // Flush destination.
    +
    13844  if(isNonCoherent)
    +
    13845  {
    +
    13846  VmaDeviceMemoryBlock* const pDstBlock = m_Blocks[move.dstBlockIndex];
    +
    13847  memRange.memory = pDstBlock->GetDeviceMemory();
    +
    13848  memRange.offset = VmaAlignDown(move.dstOffset, nonCoherentAtomSize);
    +
    13849  memRange.size = VMA_MIN(
    +
    13850  VmaAlignUp(move.size + (move.dstOffset - memRange.offset), nonCoherentAtomSize),
    +
    13851  pDstBlock->m_pMetadata->GetSize() - memRange.offset);
    +
    13852  (*m_hAllocator->GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
    +
    13853  }
    +
    13854  }
    +
    13855  }
    +
    13856 
    +
    13857  // Go over all blocks in reverse order. Unmap those that were mapped just for defragmentation.
    +
    13858  // Regardless of pCtx->res == VK_SUCCESS.
    +
    13859  for(size_t blockIndex = blockCount; blockIndex--; )
    +
    13860  {
    +
    13861  const BlockInfo& currBlockInfo = blockInfo[blockIndex];
    +
    13862  if((currBlockInfo.flags & BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION) != 0)
    +
    13863  {
    +
    13864  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    +
    13865  pBlock->Unmap(m_hAllocator, 1);
    +
    13866  }
    +
    13867  }
    +
    13868 }
    +
    13869 
    +
    13870 void VmaBlockVector::ApplyDefragmentationMovesGpu(
    +
    13871  class VmaBlockVectorDefragmentationContext* pDefragCtx,
    +
    13872  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    13873  VkCommandBuffer commandBuffer)
    +
    13874 {
    +
    13875  const size_t blockCount = m_Blocks.size();
    +
    13876 
    +
    13877  pDefragCtx->blockContexts.resize(blockCount);
    +
    13878  memset(pDefragCtx->blockContexts.data(), 0, blockCount * sizeof(VmaBlockDefragmentationContext));
    +
    13879 
    +
    13880  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
    +
    13881  const size_t moveCount = moves.size();
    +
    13882  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    +
    13883  {
    +
    13884  const VmaDefragmentationMove& move = moves[moveIndex];
    13885 
    -
    13886  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
    +
    13886  //if(move.type == VMA_ALLOCATION_TYPE_UNKNOWN)
    13887  {
    -
    13888  VmaBlockDefragmentationContext& currBlockCtx = pDefragCtx->blockContexts[blockIndex];
    -
    13889  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    -
    13890  if((currBlockCtx.flags & VmaBlockDefragmentationContext::BLOCK_FLAG_USED) != 0)
    -
    13891  {
    -
    13892  bufCreateInfo.size = pBlock->m_pMetadata->GetSize();
    -
    13893  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkCreateBuffer)(
    -
    13894  m_hAllocator->m_hDevice, &bufCreateInfo, m_hAllocator->GetAllocationCallbacks(), &currBlockCtx.hBuffer);
    -
    13895  if(pDefragCtx->res == VK_SUCCESS)
    -
    13896  {
    -
    13897  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkBindBufferMemory)(
    -
    13898  m_hAllocator->m_hDevice, currBlockCtx.hBuffer, pBlock->GetDeviceMemory(), 0);
    -
    13899  }
    -
    13900  }
    -
    13901  }
    -
    13902  }
    -
    13903 
    -
    13904  // Go over all moves. Post data transfer commands to command buffer.
    -
    13905  if(pDefragCtx->res == VK_SUCCESS)
    -
    13906  {
    -
    13907  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    -
    13908  {
    -
    13909  const VmaDefragmentationMove& move = moves[moveIndex];
    -
    13910 
    -
    13911  const VmaBlockDefragmentationContext& srcBlockCtx = pDefragCtx->blockContexts[move.srcBlockIndex];
    -
    13912  const VmaBlockDefragmentationContext& dstBlockCtx = pDefragCtx->blockContexts[move.dstBlockIndex];
    -
    13913 
    -
    13914  VMA_ASSERT(srcBlockCtx.hBuffer && dstBlockCtx.hBuffer);
    -
    13915 
    -
    13916  VkBufferCopy region = {
    -
    13917  move.srcOffset,
    -
    13918  move.dstOffset,
    -
    13919  move.size };
    -
    13920  (*m_hAllocator->GetVulkanFunctions().vkCmdCopyBuffer)(
    -
    13921  commandBuffer, srcBlockCtx.hBuffer, dstBlockCtx.hBuffer, 1, &region);
    -
    13922  }
    -
    13923  }
    -
    13924 
    -
    13925  // Save buffers to defrag context for later destruction.
    -
    13926  if(pDefragCtx->res == VK_SUCCESS && moveCount > 0)
    -
    13927  {
    -
    13928  pDefragCtx->res = VK_NOT_READY;
    -
    13929  }
    -
    13930 }
    -
    13931 
    -
    13932 void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats)
    -
    13933 {
    -
    13934  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
    -
    13935  {
    -
    13936  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    -
    13937  if(pBlock->m_pMetadata->IsEmpty())
    -
    13938  {
    -
    13939  if(m_Blocks.size() > m_MinBlockCount)
    -
    13940  {
    -
    13941  if(pDefragmentationStats != VMA_NULL)
    -
    13942  {
    -
    13943  ++pDefragmentationStats->deviceMemoryBlocksFreed;
    -
    13944  pDefragmentationStats->bytesFreed += pBlock->m_pMetadata->GetSize();
    -
    13945  }
    +
    13888  // Old school move still require us to map the whole block
    +
    13889  pDefragCtx->blockContexts[move.srcBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
    +
    13890  pDefragCtx->blockContexts[move.dstBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
    +
    13891  }
    +
    13892  }
    +
    13893 
    +
    13894  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
    +
    13895 
    +
    13896  // Go over all blocks. Create and bind buffer for whole block if necessary.
    +
    13897  {
    +
    13898  VkBufferCreateInfo bufCreateInfo;
    +
    13899  VmaFillGpuDefragmentationBufferCreateInfo(bufCreateInfo);
    +
    13900 
    +
    13901  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
    +
    13902  {
    +
    13903  VmaBlockDefragmentationContext& currBlockCtx = pDefragCtx->blockContexts[blockIndex];
    +
    13904  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    +
    13905  if((currBlockCtx.flags & VmaBlockDefragmentationContext::BLOCK_FLAG_USED) != 0)
    +
    13906  {
    +
    13907  bufCreateInfo.size = pBlock->m_pMetadata->GetSize();
    +
    13908  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkCreateBuffer)(
    +
    13909  m_hAllocator->m_hDevice, &bufCreateInfo, m_hAllocator->GetAllocationCallbacks(), &currBlockCtx.hBuffer);
    +
    13910  if(pDefragCtx->res == VK_SUCCESS)
    +
    13911  {
    +
    13912  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkBindBufferMemory)(
    +
    13913  m_hAllocator->m_hDevice, currBlockCtx.hBuffer, pBlock->GetDeviceMemory(), 0);
    +
    13914  }
    +
    13915  }
    +
    13916  }
    +
    13917  }
    +
    13918 
    +
    13919  // Go over all moves. Post data transfer commands to command buffer.
    +
    13920  if(pDefragCtx->res == VK_SUCCESS)
    +
    13921  {
    +
    13922  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
    +
    13923  {
    +
    13924  const VmaDefragmentationMove& move = moves[moveIndex];
    +
    13925 
    +
    13926  const VmaBlockDefragmentationContext& srcBlockCtx = pDefragCtx->blockContexts[move.srcBlockIndex];
    +
    13927  const VmaBlockDefragmentationContext& dstBlockCtx = pDefragCtx->blockContexts[move.dstBlockIndex];
    +
    13928 
    +
    13929  VMA_ASSERT(srcBlockCtx.hBuffer && dstBlockCtx.hBuffer);
    +
    13930 
    +
    13931  VkBufferCopy region = {
    +
    13932  move.srcOffset,
    +
    13933  move.dstOffset,
    +
    13934  move.size };
    +
    13935  (*m_hAllocator->GetVulkanFunctions().vkCmdCopyBuffer)(
    +
    13936  commandBuffer, srcBlockCtx.hBuffer, dstBlockCtx.hBuffer, 1, &region);
    +
    13937  }
    +
    13938  }
    +
    13939 
    +
    13940  // Save buffers to defrag context for later destruction.
    +
    13941  if(pDefragCtx->res == VK_SUCCESS && moveCount > 0)
    +
    13942  {
    +
    13943  pDefragCtx->res = VK_NOT_READY;
    +
    13944  }
    +
    13945 }
    13946 
    -
    13947  VmaVectorRemove(m_Blocks, blockIndex);
    -
    13948  pBlock->Destroy(m_hAllocator);
    -
    13949  vma_delete(m_hAllocator, pBlock);
    -
    13950  }
    -
    13951  else
    -
    13952  {
    -
    13953  break;
    -
    13954  }
    -
    13955  }
    -
    13956  }
    -
    13957  UpdateHasEmptyBlock();
    -
    13958 }
    -
    13959 
    -
    13960 void VmaBlockVector::UpdateHasEmptyBlock()
    -
    13961 {
    -
    13962  m_HasEmptyBlock = false;
    -
    13963  for(size_t index = 0, count = m_Blocks.size(); index < count; ++index)
    -
    13964  {
    -
    13965  VmaDeviceMemoryBlock* const pBlock = m_Blocks[index];
    -
    13966  if(pBlock->m_pMetadata->IsEmpty())
    -
    13967  {
    -
    13968  m_HasEmptyBlock = true;
    -
    13969  break;
    +
    13947 void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats)
    +
    13948 {
    +
    13949  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
    +
    13950  {
    +
    13951  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
    +
    13952  if(pBlock->m_pMetadata->IsEmpty())
    +
    13953  {
    +
    13954  if(m_Blocks.size() > m_MinBlockCount)
    +
    13955  {
    +
    13956  if(pDefragmentationStats != VMA_NULL)
    +
    13957  {
    +
    13958  ++pDefragmentationStats->deviceMemoryBlocksFreed;
    +
    13959  pDefragmentationStats->bytesFreed += pBlock->m_pMetadata->GetSize();
    +
    13960  }
    +
    13961 
    +
    13962  VmaVectorRemove(m_Blocks, blockIndex);
    +
    13963  pBlock->Destroy(m_hAllocator);
    +
    13964  vma_delete(m_hAllocator, pBlock);
    +
    13965  }
    +
    13966  else
    +
    13967  {
    +
    13968  break;
    +
    13969  }
    13970  }
    13971  }
    -
    13972 }
    -
    13973 
    -
    13974 #if VMA_STATS_STRING_ENABLED
    -
    13975 
    -
    13976 void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
    -
    13977 {
    -
    13978  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    13979 
    -
    13980  json.BeginObject();
    -
    13981 
    -
    13982  if(IsCustomPool())
    -
    13983  {
    -
    13984  const char* poolName = m_hParentPool->GetName();
    -
    13985  if(poolName != VMA_NULL && poolName[0] != '\0')
    -
    13986  {
    -
    13987  json.WriteString("Name");
    -
    13988  json.WriteString(poolName);
    -
    13989  }
    +
    13972  UpdateHasEmptyBlock();
    +
    13973 }
    +
    13974 
    +
    13975 void VmaBlockVector::UpdateHasEmptyBlock()
    +
    13976 {
    +
    13977  m_HasEmptyBlock = false;
    +
    13978  for(size_t index = 0, count = m_Blocks.size(); index < count; ++index)
    +
    13979  {
    +
    13980  VmaDeviceMemoryBlock* const pBlock = m_Blocks[index];
    +
    13981  if(pBlock->m_pMetadata->IsEmpty())
    +
    13982  {
    +
    13983  m_HasEmptyBlock = true;
    +
    13984  break;
    +
    13985  }
    +
    13986  }
    +
    13987 }
    +
    13988 
    +
    13989 #if VMA_STATS_STRING_ENABLED
    13990 
    -
    13991  json.WriteString("MemoryTypeIndex");
    -
    13992  json.WriteNumber(m_MemoryTypeIndex);
    -
    13993 
    -
    13994  json.WriteString("BlockSize");
    -
    13995  json.WriteNumber(m_PreferredBlockSize);
    +
    13991 void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
    +
    13992 {
    +
    13993  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    13994 
    +
    13995  json.BeginObject();
    13996 
    -
    13997  json.WriteString("BlockCount");
    -
    13998  json.BeginObject(true);
    -
    13999  if(m_MinBlockCount > 0)
    -
    14000  {
    -
    14001  json.WriteString("Min");
    -
    14002  json.WriteNumber((uint64_t)m_MinBlockCount);
    -
    14003  }
    -
    14004  if(m_MaxBlockCount < SIZE_MAX)
    -
    14005  {
    -
    14006  json.WriteString("Max");
    -
    14007  json.WriteNumber((uint64_t)m_MaxBlockCount);
    -
    14008  }
    -
    14009  json.WriteString("Cur");
    -
    14010  json.WriteNumber((uint64_t)m_Blocks.size());
    -
    14011  json.EndObject();
    -
    14012 
    -
    14013  if(m_FrameInUseCount > 0)
    -
    14014  {
    -
    14015  json.WriteString("FrameInUseCount");
    -
    14016  json.WriteNumber(m_FrameInUseCount);
    -
    14017  }
    -
    14018 
    -
    14019  if(m_Algorithm != 0)
    +
    13997  if(IsCustomPool())
    +
    13998  {
    +
    13999  const char* poolName = m_hParentPool->GetName();
    +
    14000  if(poolName != VMA_NULL && poolName[0] != '\0')
    +
    14001  {
    +
    14002  json.WriteString("Name");
    +
    14003  json.WriteString(poolName);
    +
    14004  }
    +
    14005 
    +
    14006  json.WriteString("MemoryTypeIndex");
    +
    14007  json.WriteNumber(m_MemoryTypeIndex);
    +
    14008 
    +
    14009  json.WriteString("BlockSize");
    +
    14010  json.WriteNumber(m_PreferredBlockSize);
    +
    14011 
    +
    14012  json.WriteString("BlockCount");
    +
    14013  json.BeginObject(true);
    +
    14014  if(m_MinBlockCount > 0)
    +
    14015  {
    +
    14016  json.WriteString("Min");
    +
    14017  json.WriteNumber((uint64_t)m_MinBlockCount);
    +
    14018  }
    +
    14019  if(m_MaxBlockCount < SIZE_MAX)
    14020  {
    -
    14021  json.WriteString("Algorithm");
    -
    14022  json.WriteString(VmaAlgorithmToStr(m_Algorithm));
    +
    14021  json.WriteString("Max");
    +
    14022  json.WriteNumber((uint64_t)m_MaxBlockCount);
    14023  }
    -
    14024  }
    -
    14025  else
    -
    14026  {
    -
    14027  json.WriteString("PreferredBlockSize");
    -
    14028  json.WriteNumber(m_PreferredBlockSize);
    -
    14029  }
    -
    14030 
    -
    14031  json.WriteString("Blocks");
    -
    14032  json.BeginObject();
    -
    14033  for(size_t i = 0; i < m_Blocks.size(); ++i)
    -
    14034  {
    -
    14035  json.BeginString();
    -
    14036  json.ContinueString(m_Blocks[i]->GetId());
    -
    14037  json.EndString();
    -
    14038 
    -
    14039  m_Blocks[i]->m_pMetadata->PrintDetailedMap(json);
    -
    14040  }
    -
    14041  json.EndObject();
    -
    14042 
    -
    14043  json.EndObject();
    -
    14044 }
    +
    14024  json.WriteString("Cur");
    +
    14025  json.WriteNumber((uint64_t)m_Blocks.size());
    +
    14026  json.EndObject();
    +
    14027 
    +
    14028  if(m_FrameInUseCount > 0)
    +
    14029  {
    +
    14030  json.WriteString("FrameInUseCount");
    +
    14031  json.WriteNumber(m_FrameInUseCount);
    +
    14032  }
    +
    14033 
    +
    14034  if(m_Algorithm != 0)
    +
    14035  {
    +
    14036  json.WriteString("Algorithm");
    +
    14037  json.WriteString(VmaAlgorithmToStr(m_Algorithm));
    +
    14038  }
    +
    14039  }
    +
    14040  else
    +
    14041  {
    +
    14042  json.WriteString("PreferredBlockSize");
    +
    14043  json.WriteNumber(m_PreferredBlockSize);
    +
    14044  }
    14045 
    -
    14046 #endif // #if VMA_STATS_STRING_ENABLED
    -
    14047 
    -
    14048 void VmaBlockVector::Defragment(
    -
    14049  class VmaBlockVectorDefragmentationContext* pCtx,
    -
    14050  VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags,
    -
    14051  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
    -
    14052  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
    -
    14053  VkCommandBuffer commandBuffer)
    -
    14054 {
    -
    14055  pCtx->res = VK_SUCCESS;
    -
    14056 
    -
    14057  const VkMemoryPropertyFlags memPropFlags =
    -
    14058  m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags;
    -
    14059  const bool isHostVisible = (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
    +
    14046  json.WriteString("Blocks");
    +
    14047  json.BeginObject();
    +
    14048  for(size_t i = 0; i < m_Blocks.size(); ++i)
    +
    14049  {
    +
    14050  json.BeginString();
    +
    14051  json.ContinueString(m_Blocks[i]->GetId());
    +
    14052  json.EndString();
    +
    14053 
    +
    14054  m_Blocks[i]->m_pMetadata->PrintDetailedMap(json);
    +
    14055  }
    +
    14056  json.EndObject();
    +
    14057 
    +
    14058  json.EndObject();
    +
    14059 }
    14060 
    -
    14061  const bool canDefragmentOnCpu = maxCpuBytesToMove > 0 && maxCpuAllocationsToMove > 0 &&
    -
    14062  isHostVisible;
    -
    14063  const bool canDefragmentOnGpu = maxGpuBytesToMove > 0 && maxGpuAllocationsToMove > 0 &&
    -
    14064  !IsCorruptionDetectionEnabled() &&
    -
    14065  ((1u << m_MemoryTypeIndex) & m_hAllocator->GetGpuDefragmentationMemoryTypeBits()) != 0;
    -
    14066 
    -
    14067  // There are options to defragment this memory type.
    -
    14068  if(canDefragmentOnCpu || canDefragmentOnGpu)
    -
    14069  {
    -
    14070  bool defragmentOnGpu;
    -
    14071  // There is only one option to defragment this memory type.
    -
    14072  if(canDefragmentOnGpu != canDefragmentOnCpu)
    -
    14073  {
    -
    14074  defragmentOnGpu = canDefragmentOnGpu;
    -
    14075  }
    -
    14076  // Both options are available: Heuristics to choose the best one.
    -
    14077  else
    -
    14078  {
    -
    14079  defragmentOnGpu = (memPropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 ||
    -
    14080  m_hAllocator->IsIntegratedGpu();
    -
    14081  }
    -
    14082 
    -
    14083  bool overlappingMoveSupported = !defragmentOnGpu;
    -
    14084 
    -
    14085  if(m_hAllocator->m_UseMutex)
    -
    14086  {
    -
    14087  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)
    -
    14088  {
    -
    14089  if(!m_Mutex.TryLockWrite())
    -
    14090  {
    -
    14091  pCtx->res = VK_ERROR_INITIALIZATION_FAILED;
    -
    14092  return;
    -
    14093  }
    -
    14094  }
    -
    14095  else
    -
    14096  {
    -
    14097  m_Mutex.LockWrite();
    -
    14098  pCtx->mutexLocked = true;
    -
    14099  }
    -
    14100  }
    -
    14101 
    -
    14102  pCtx->Begin(overlappingMoveSupported, flags);
    -
    14103 
    -
    14104  // Defragment.
    -
    14105 
    -
    14106  const VkDeviceSize maxBytesToMove = defragmentOnGpu ? maxGpuBytesToMove : maxCpuBytesToMove;
    -
    14107  const uint32_t maxAllocationsToMove = defragmentOnGpu ? maxGpuAllocationsToMove : maxCpuAllocationsToMove;
    -
    14108  pCtx->res = pCtx->GetAlgorithm()->Defragment(pCtx->defragmentationMoves, maxBytesToMove, maxAllocationsToMove, flags);
    -
    14109 
    -
    14110  // Accumulate statistics.
    -
    14111  if(pStats != VMA_NULL)
    -
    14112  {
    -
    14113  const VkDeviceSize bytesMoved = pCtx->GetAlgorithm()->GetBytesMoved();
    -
    14114  const uint32_t allocationsMoved = pCtx->GetAlgorithm()->GetAllocationsMoved();
    -
    14115  pStats->bytesMoved += bytesMoved;
    -
    14116  pStats->allocationsMoved += allocationsMoved;
    -
    14117  VMA_ASSERT(bytesMoved <= maxBytesToMove);
    -
    14118  VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
    -
    14119  if(defragmentOnGpu)
    -
    14120  {
    -
    14121  maxGpuBytesToMove -= bytesMoved;
    -
    14122  maxGpuAllocationsToMove -= allocationsMoved;
    -
    14123  }
    -
    14124  else
    -
    14125  {
    -
    14126  maxCpuBytesToMove -= bytesMoved;
    -
    14127  maxCpuAllocationsToMove -= allocationsMoved;
    -
    14128  }
    -
    14129  }
    -
    14130 
    -
    14131  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)
    -
    14132  {
    -
    14133  if(m_hAllocator->m_UseMutex)
    -
    14134  m_Mutex.UnlockWrite();
    -
    14135 
    -
    14136  if(pCtx->res >= VK_SUCCESS && !pCtx->defragmentationMoves.empty())
    -
    14137  pCtx->res = VK_NOT_READY;
    -
    14138 
    -
    14139  return;
    -
    14140  }
    -
    14141 
    -
    14142  if(pCtx->res >= VK_SUCCESS)
    -
    14143  {
    -
    14144  if(defragmentOnGpu)
    -
    14145  {
    -
    14146  ApplyDefragmentationMovesGpu(pCtx, pCtx->defragmentationMoves, commandBuffer);
    -
    14147  }
    -
    14148  else
    -
    14149  {
    -
    14150  ApplyDefragmentationMovesCpu(pCtx, pCtx->defragmentationMoves);
    -
    14151  }
    -
    14152  }
    -
    14153  }
    -
    14154 }
    -
    14155 
    -
    14156 void VmaBlockVector::DefragmentationEnd(
    -
    14157  class VmaBlockVectorDefragmentationContext* pCtx,
    -
    14158  uint32_t flags,
    -
    14159  VmaDefragmentationStats* pStats)
    -
    14160 {
    -
    14161  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL && m_hAllocator->m_UseMutex)
    -
    14162  {
    -
    14163  VMA_ASSERT(pCtx->mutexLocked == false);
    -
    14164 
    -
    14165  // Incremental defragmentation doesn't hold the lock, so when we enter here we don't actually have any
    -
    14166  // lock protecting us. Since we mutate state here, we have to take the lock out now
    -
    14167  m_Mutex.LockWrite();
    -
    14168  pCtx->mutexLocked = true;
    -
    14169  }
    +
    14061 #endif // #if VMA_STATS_STRING_ENABLED
    +
    14062 
    +
    14063 void VmaBlockVector::Defragment(
    +
    14064  class VmaBlockVectorDefragmentationContext* pCtx,
    +
    14065  VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags,
    +
    14066  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
    +
    14067  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
    +
    14068  VkCommandBuffer commandBuffer)
    +
    14069 {
    +
    14070  pCtx->res = VK_SUCCESS;
    +
    14071 
    +
    14072  const VkMemoryPropertyFlags memPropFlags =
    +
    14073  m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags;
    +
    14074  const bool isHostVisible = (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
    +
    14075 
    +
    14076  const bool canDefragmentOnCpu = maxCpuBytesToMove > 0 && maxCpuAllocationsToMove > 0 &&
    +
    14077  isHostVisible;
    +
    14078  const bool canDefragmentOnGpu = maxGpuBytesToMove > 0 && maxGpuAllocationsToMove > 0 &&
    +
    14079  !IsCorruptionDetectionEnabled() &&
    +
    14080  ((1u << m_MemoryTypeIndex) & m_hAllocator->GetGpuDefragmentationMemoryTypeBits()) != 0;
    +
    14081 
    +
    14082  // There are options to defragment this memory type.
    +
    14083  if(canDefragmentOnCpu || canDefragmentOnGpu)
    +
    14084  {
    +
    14085  bool defragmentOnGpu;
    +
    14086  // There is only one option to defragment this memory type.
    +
    14087  if(canDefragmentOnGpu != canDefragmentOnCpu)
    +
    14088  {
    +
    14089  defragmentOnGpu = canDefragmentOnGpu;
    +
    14090  }
    +
    14091  // Both options are available: Heuristics to choose the best one.
    +
    14092  else
    +
    14093  {
    +
    14094  defragmentOnGpu = (memPropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 ||
    +
    14095  m_hAllocator->IsIntegratedGpu();
    +
    14096  }
    +
    14097 
    +
    14098  bool overlappingMoveSupported = !defragmentOnGpu;
    +
    14099 
    +
    14100  if(m_hAllocator->m_UseMutex)
    +
    14101  {
    +
    14102  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)
    +
    14103  {
    +
    14104  if(!m_Mutex.TryLockWrite())
    +
    14105  {
    +
    14106  pCtx->res = VK_ERROR_INITIALIZATION_FAILED;
    +
    14107  return;
    +
    14108  }
    +
    14109  }
    +
    14110  else
    +
    14111  {
    +
    14112  m_Mutex.LockWrite();
    +
    14113  pCtx->mutexLocked = true;
    +
    14114  }
    +
    14115  }
    +
    14116 
    +
    14117  pCtx->Begin(overlappingMoveSupported, flags);
    +
    14118 
    +
    14119  // Defragment.
    +
    14120 
    +
    14121  const VkDeviceSize maxBytesToMove = defragmentOnGpu ? maxGpuBytesToMove : maxCpuBytesToMove;
    +
    14122  const uint32_t maxAllocationsToMove = defragmentOnGpu ? maxGpuAllocationsToMove : maxCpuAllocationsToMove;
    +
    14123  pCtx->res = pCtx->GetAlgorithm()->Defragment(pCtx->defragmentationMoves, maxBytesToMove, maxAllocationsToMove, flags);
    +
    14124 
    +
    14125  // Accumulate statistics.
    +
    14126  if(pStats != VMA_NULL)
    +
    14127  {
    +
    14128  const VkDeviceSize bytesMoved = pCtx->GetAlgorithm()->GetBytesMoved();
    +
    14129  const uint32_t allocationsMoved = pCtx->GetAlgorithm()->GetAllocationsMoved();
    +
    14130  pStats->bytesMoved += bytesMoved;
    +
    14131  pStats->allocationsMoved += allocationsMoved;
    +
    14132  VMA_ASSERT(bytesMoved <= maxBytesToMove);
    +
    14133  VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
    +
    14134  if(defragmentOnGpu)
    +
    14135  {
    +
    14136  maxGpuBytesToMove -= bytesMoved;
    +
    14137  maxGpuAllocationsToMove -= allocationsMoved;
    +
    14138  }
    +
    14139  else
    +
    14140  {
    +
    14141  maxCpuBytesToMove -= bytesMoved;
    +
    14142  maxCpuAllocationsToMove -= allocationsMoved;
    +
    14143  }
    +
    14144  }
    +
    14145 
    +
    14146  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)
    +
    14147  {
    +
    14148  if(m_hAllocator->m_UseMutex)
    +
    14149  m_Mutex.UnlockWrite();
    +
    14150 
    +
    14151  if(pCtx->res >= VK_SUCCESS && !pCtx->defragmentationMoves.empty())
    +
    14152  pCtx->res = VK_NOT_READY;
    +
    14153 
    +
    14154  return;
    +
    14155  }
    +
    14156 
    +
    14157  if(pCtx->res >= VK_SUCCESS)
    +
    14158  {
    +
    14159  if(defragmentOnGpu)
    +
    14160  {
    +
    14161  ApplyDefragmentationMovesGpu(pCtx, pCtx->defragmentationMoves, commandBuffer);
    +
    14162  }
    +
    14163  else
    +
    14164  {
    +
    14165  ApplyDefragmentationMovesCpu(pCtx, pCtx->defragmentationMoves);
    +
    14166  }
    +
    14167  }
    +
    14168  }
    +
    14169 }
    14170 
    -
    14171  // If the mutex isn't locked we didn't do any work and there is nothing to delete.
    -
    14172  if(pCtx->mutexLocked || !m_hAllocator->m_UseMutex)
    -
    14173  {
    -
    14174  // Destroy buffers.
    -
    14175  for(size_t blockIndex = pCtx->blockContexts.size(); blockIndex--;)
    -
    14176  {
    -
    14177  VmaBlockDefragmentationContext &blockCtx = pCtx->blockContexts[blockIndex];
    -
    14178  if(blockCtx.hBuffer)
    -
    14179  {
    -
    14180  (*m_hAllocator->GetVulkanFunctions().vkDestroyBuffer)(m_hAllocator->m_hDevice, blockCtx.hBuffer, m_hAllocator->GetAllocationCallbacks());
    -
    14181  }
    -
    14182  }
    -
    14183 
    -
    14184  if(pCtx->res >= VK_SUCCESS)
    -
    14185  {
    -
    14186  FreeEmptyBlocks(pStats);
    -
    14187  }
    -
    14188  }
    -
    14189 
    -
    14190  if(pCtx->mutexLocked)
    -
    14191  {
    -
    14192  VMA_ASSERT(m_hAllocator->m_UseMutex);
    -
    14193  m_Mutex.UnlockWrite();
    -
    14194  }
    -
    14195 }
    -
    14196 
    -
    14197 uint32_t VmaBlockVector::ProcessDefragmentations(
    -
    14198  class VmaBlockVectorDefragmentationContext *pCtx,
    -
    14199  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves)
    -
    14200 {
    -
    14201  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    14202 
    -
    14203  const uint32_t moveCount = VMA_MIN(uint32_t(pCtx->defragmentationMoves.size()) - pCtx->defragmentationMovesProcessed, maxMoves);
    +
    14171 void VmaBlockVector::DefragmentationEnd(
    +
    14172  class VmaBlockVectorDefragmentationContext* pCtx,
    +
    14173  uint32_t flags,
    +
    14174  VmaDefragmentationStats* pStats)
    +
    14175 {
    +
    14176  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL && m_hAllocator->m_UseMutex)
    +
    14177  {
    +
    14178  VMA_ASSERT(pCtx->mutexLocked == false);
    +
    14179 
    +
    14180  // Incremental defragmentation doesn't hold the lock, so when we enter here we don't actually have any
    +
    14181  // lock protecting us. Since we mutate state here, we have to take the lock out now
    +
    14182  m_Mutex.LockWrite();
    +
    14183  pCtx->mutexLocked = true;
    +
    14184  }
    +
    14185 
    +
    14186  // If the mutex isn't locked we didn't do any work and there is nothing to delete.
    +
    14187  if(pCtx->mutexLocked || !m_hAllocator->m_UseMutex)
    +
    14188  {
    +
    14189  // Destroy buffers.
    +
    14190  for(size_t blockIndex = pCtx->blockContexts.size(); blockIndex--;)
    +
    14191  {
    +
    14192  VmaBlockDefragmentationContext &blockCtx = pCtx->blockContexts[blockIndex];
    +
    14193  if(blockCtx.hBuffer)
    +
    14194  {
    +
    14195  (*m_hAllocator->GetVulkanFunctions().vkDestroyBuffer)(m_hAllocator->m_hDevice, blockCtx.hBuffer, m_hAllocator->GetAllocationCallbacks());
    +
    14196  }
    +
    14197  }
    +
    14198 
    +
    14199  if(pCtx->res >= VK_SUCCESS)
    +
    14200  {
    +
    14201  FreeEmptyBlocks(pStats);
    +
    14202  }
    +
    14203  }
    14204 
    -
    14205  for(uint32_t i = 0; i < moveCount; ++ i)
    +
    14205  if(pCtx->mutexLocked)
    14206  {
    -
    14207  VmaDefragmentationMove& move = pCtx->defragmentationMoves[pCtx->defragmentationMovesProcessed + i];
    -
    14208 
    -
    14209  pMove->allocation = move.hAllocation;
    -
    14210  pMove->memory = move.pDstBlock->GetDeviceMemory();
    -
    14211  pMove->offset = move.dstOffset;
    -
    14212 
    -
    14213  ++ pMove;
    -
    14214  }
    -
    14215 
    -
    14216  pCtx->defragmentationMovesProcessed += moveCount;
    +
    14207  VMA_ASSERT(m_hAllocator->m_UseMutex);
    +
    14208  m_Mutex.UnlockWrite();
    +
    14209  }
    +
    14210 }
    +
    14211 
    +
    14212 uint32_t VmaBlockVector::ProcessDefragmentations(
    +
    14213  class VmaBlockVectorDefragmentationContext *pCtx,
    +
    14214  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves)
    +
    14215 {
    +
    14216  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    14217 
    -
    14218  return moveCount;
    -
    14219 }
    -
    14220 
    -
    14221 void VmaBlockVector::CommitDefragmentations(
    -
    14222  class VmaBlockVectorDefragmentationContext *pCtx,
    -
    14223  VmaDefragmentationStats* pStats)
    -
    14224 {
    -
    14225  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    14226 
    -
    14227  for(uint32_t i = pCtx->defragmentationMovesCommitted; i < pCtx->defragmentationMovesProcessed; ++ i)
    -
    14228  {
    -
    14229  const VmaDefragmentationMove &move = pCtx->defragmentationMoves[i];
    +
    14218  const uint32_t moveCount = VMA_MIN(uint32_t(pCtx->defragmentationMoves.size()) - pCtx->defragmentationMovesProcessed, maxMoves);
    +
    14219 
    +
    14220  for(uint32_t i = 0; i < moveCount; ++ i)
    +
    14221  {
    +
    14222  VmaDefragmentationMove& move = pCtx->defragmentationMoves[pCtx->defragmentationMovesProcessed + i];
    +
    14223 
    +
    14224  pMove->allocation = move.hAllocation;
    +
    14225  pMove->memory = move.pDstBlock->GetDeviceMemory();
    +
    14226  pMove->offset = move.dstOffset;
    +
    14227 
    +
    14228  ++ pMove;
    +
    14229  }
    14230 
    -
    14231  move.pSrcBlock->m_pMetadata->FreeAtOffset(move.srcOffset);
    -
    14232  move.hAllocation->ChangeBlockAllocation(m_hAllocator, move.pDstBlock, move.dstOffset);
    -
    14233  }
    -
    14234 
    -
    14235  pCtx->defragmentationMovesCommitted = pCtx->defragmentationMovesProcessed;
    -
    14236  FreeEmptyBlocks(pStats);
    -
    14237 }
    -
    14238 
    -
    14239 size_t VmaBlockVector::CalcAllocationCount() const
    -
    14240 {
    -
    14241  size_t result = 0;
    -
    14242  for(size_t i = 0; i < m_Blocks.size(); ++i)
    +
    14231  pCtx->defragmentationMovesProcessed += moveCount;
    +
    14232 
    +
    14233  return moveCount;
    +
    14234 }
    +
    14235 
    +
    14236 void VmaBlockVector::CommitDefragmentations(
    +
    14237  class VmaBlockVectorDefragmentationContext *pCtx,
    +
    14238  VmaDefragmentationStats* pStats)
    +
    14239 {
    +
    14240  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    14241 
    +
    14242  for(uint32_t i = pCtx->defragmentationMovesCommitted; i < pCtx->defragmentationMovesProcessed; ++ i)
    14243  {
    -
    14244  result += m_Blocks[i]->m_pMetadata->GetAllocationCount();
    -
    14245  }
    -
    14246  return result;
    -
    14247 }
    -
    14248 
    -
    14249 bool VmaBlockVector::IsBufferImageGranularityConflictPossible() const
    -
    14250 {
    -
    14251  if(m_BufferImageGranularity == 1)
    -
    14252  {
    -
    14253  return false;
    -
    14254  }
    -
    14255  VmaSuballocationType lastSuballocType = VMA_SUBALLOCATION_TYPE_FREE;
    -
    14256  for(size_t i = 0, count = m_Blocks.size(); i < count; ++i)
    -
    14257  {
    -
    14258  VmaDeviceMemoryBlock* const pBlock = m_Blocks[i];
    -
    14259  VMA_ASSERT(m_Algorithm == 0);
    -
    14260  VmaBlockMetadata_Generic* const pMetadata = (VmaBlockMetadata_Generic*)pBlock->m_pMetadata;
    -
    14261  if(pMetadata->IsBufferImageGranularityConflictPossible(m_BufferImageGranularity, lastSuballocType))
    -
    14262  {
    -
    14263  return true;
    -
    14264  }
    -
    14265  }
    -
    14266  return false;
    -
    14267 }
    -
    14268 
    -
    14269 void VmaBlockVector::MakePoolAllocationsLost(
    -
    14270  uint32_t currentFrameIndex,
    -
    14271  size_t* pLostAllocationCount)
    -
    14272 {
    -
    14273  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    14274  size_t lostAllocationCount = 0;
    -
    14275  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    -
    14276  {
    -
    14277  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    -
    14278  VMA_ASSERT(pBlock);
    -
    14279  lostAllocationCount += pBlock->m_pMetadata->MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount);
    +
    14244  const VmaDefragmentationMove &move = pCtx->defragmentationMoves[i];
    +
    14245 
    +
    14246  move.pSrcBlock->m_pMetadata->FreeAtOffset(move.srcOffset);
    +
    14247  move.hAllocation->ChangeBlockAllocation(m_hAllocator, move.pDstBlock, move.dstOffset);
    +
    14248  }
    +
    14249 
    +
    14250  pCtx->defragmentationMovesCommitted = pCtx->defragmentationMovesProcessed;
    +
    14251  FreeEmptyBlocks(pStats);
    +
    14252 }
    +
    14253 
    +
    14254 size_t VmaBlockVector::CalcAllocationCount() const
    +
    14255 {
    +
    14256  size_t result = 0;
    +
    14257  for(size_t i = 0; i < m_Blocks.size(); ++i)
    +
    14258  {
    +
    14259  result += m_Blocks[i]->m_pMetadata->GetAllocationCount();
    +
    14260  }
    +
    14261  return result;
    +
    14262 }
    +
    14263 
    +
    14264 bool VmaBlockVector::IsBufferImageGranularityConflictPossible() const
    +
    14265 {
    +
    14266  if(m_BufferImageGranularity == 1)
    +
    14267  {
    +
    14268  return false;
    +
    14269  }
    +
    14270  VmaSuballocationType lastSuballocType = VMA_SUBALLOCATION_TYPE_FREE;
    +
    14271  for(size_t i = 0, count = m_Blocks.size(); i < count; ++i)
    +
    14272  {
    +
    14273  VmaDeviceMemoryBlock* const pBlock = m_Blocks[i];
    +
    14274  VMA_ASSERT(m_Algorithm == 0);
    +
    14275  VmaBlockMetadata_Generic* const pMetadata = (VmaBlockMetadata_Generic*)pBlock->m_pMetadata;
    +
    14276  if(pMetadata->IsBufferImageGranularityConflictPossible(m_BufferImageGranularity, lastSuballocType))
    +
    14277  {
    +
    14278  return true;
    +
    14279  }
    14280  }
    -
    14281  if(pLostAllocationCount != VMA_NULL)
    -
    14282  {
    -
    14283  *pLostAllocationCount = lostAllocationCount;
    -
    14284  }
    -
    14285 }
    -
    14286 
    -
    14287 VkResult VmaBlockVector::CheckCorruption()
    -
    14288 {
    -
    14289  if(!IsCorruptionDetectionEnabled())
    -
    14290  {
    -
    14291  return VK_ERROR_FEATURE_NOT_PRESENT;
    -
    14292  }
    -
    14293 
    -
    14294  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    14295  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    -
    14296  {
    -
    14297  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    -
    14298  VMA_ASSERT(pBlock);
    -
    14299  VkResult res = pBlock->CheckCorruption(m_hAllocator);
    -
    14300  if(res != VK_SUCCESS)
    -
    14301  {
    -
    14302  return res;
    -
    14303  }
    -
    14304  }
    -
    14305  return VK_SUCCESS;
    -
    14306 }
    -
    14307 
    -
    14308 void VmaBlockVector::AddStats(VmaStats* pStats)
    -
    14309 {
    -
    14310  const uint32_t memTypeIndex = m_MemoryTypeIndex;
    -
    14311  const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex);
    -
    14312 
    -
    14313  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    -
    14314 
    -
    14315  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    -
    14316  {
    -
    14317  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    -
    14318  VMA_ASSERT(pBlock);
    -
    14319  VMA_HEAVY_ASSERT(pBlock->Validate());
    -
    14320  VmaStatInfo allocationStatInfo;
    -
    14321  pBlock->m_pMetadata->CalcAllocationStatInfo(allocationStatInfo);
    -
    14322  VmaAddStatInfo(pStats->total, allocationStatInfo);
    -
    14323  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
    -
    14324  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
    -
    14325  }
    -
    14326 }
    +
    14281  return false;
    +
    14282 }
    +
    14283 
    +
    14284 void VmaBlockVector::MakePoolAllocationsLost(
    +
    14285  uint32_t currentFrameIndex,
    +
    14286  size_t* pLostAllocationCount)
    +
    14287 {
    +
    14288  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    14289  size_t lostAllocationCount = 0;
    +
    14290  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    +
    14291  {
    +
    14292  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    +
    14293  VMA_ASSERT(pBlock);
    +
    14294  lostAllocationCount += pBlock->m_pMetadata->MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount);
    +
    14295  }
    +
    14296  if(pLostAllocationCount != VMA_NULL)
    +
    14297  {
    +
    14298  *pLostAllocationCount = lostAllocationCount;
    +
    14299  }
    +
    14300 }
    +
    14301 
    +
    14302 VkResult VmaBlockVector::CheckCorruption()
    +
    14303 {
    +
    14304  if(!IsCorruptionDetectionEnabled())
    +
    14305  {
    +
    14306  return VK_ERROR_FEATURE_NOT_PRESENT;
    +
    14307  }
    +
    14308 
    +
    14309  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    14310  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    +
    14311  {
    +
    14312  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    +
    14313  VMA_ASSERT(pBlock);
    +
    14314  VkResult res = pBlock->CheckCorruption(m_hAllocator);
    +
    14315  if(res != VK_SUCCESS)
    +
    14316  {
    +
    14317  return res;
    +
    14318  }
    +
    14319  }
    +
    14320  return VK_SUCCESS;
    +
    14321 }
    +
    14322 
    +
    14323 void VmaBlockVector::AddStats(VmaStats* pStats)
    +
    14324 {
    +
    14325  const uint32_t memTypeIndex = m_MemoryTypeIndex;
    +
    14326  const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex);
    14327 
    -
    14329 // VmaDefragmentationAlgorithm_Generic members definition
    -
    14330 
    -
    14331 VmaDefragmentationAlgorithm_Generic::VmaDefragmentationAlgorithm_Generic(
    -
    14332  VmaAllocator hAllocator,
    -
    14333  VmaBlockVector* pBlockVector,
    -
    14334  uint32_t currentFrameIndex,
    -
    14335  bool overlappingMoveSupported) :
    -
    14336  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
    -
    14337  m_AllocationCount(0),
    -
    14338  m_AllAllocations(false),
    -
    14339  m_BytesMoved(0),
    -
    14340  m_AllocationsMoved(0),
    -
    14341  m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))
    -
    14342 {
    -
    14343  // Create block info for each block.
    -
    14344  const size_t blockCount = m_pBlockVector->m_Blocks.size();
    -
    14345  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    -
    14346  {
    -
    14347  BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks());
    -
    14348  pBlockInfo->m_OriginalBlockIndex = blockIndex;
    -
    14349  pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex];
    -
    14350  m_Blocks.push_back(pBlockInfo);
    -
    14351  }
    -
    14352 
    -
    14353  // Sort them by m_pBlock pointer value.
    -
    14354  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
    -
    14355 }
    -
    14356 
    -
    14357 VmaDefragmentationAlgorithm_Generic::~VmaDefragmentationAlgorithm_Generic()
    -
    14358 {
    -
    14359  for(size_t i = m_Blocks.size(); i--; )
    -
    14360  {
    -
    14361  vma_delete(m_hAllocator, m_Blocks[i]);
    -
    14362  }
    -
    14363 }
    -
    14364 
    -
    14365 void VmaDefragmentationAlgorithm_Generic::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
    -
    14366 {
    -
    14367  // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost.
    -
    14368  if(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
    -
    14369  {
    -
    14370  VmaDeviceMemoryBlock* pBlock = hAlloc->GetBlock();
    -
    14371  BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
    -
    14372  if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
    -
    14373  {
    -
    14374  AllocationInfo allocInfo = AllocationInfo(hAlloc, pChanged);
    -
    14375  (*it)->m_Allocations.push_back(allocInfo);
    -
    14376  }
    -
    14377  else
    -
    14378  {
    -
    14379  VMA_ASSERT(0);
    -
    14380  }
    -
    14381 
    -
    14382  ++m_AllocationCount;
    -
    14383  }
    -
    14384 }
    -
    14385 
    -
    14386 VkResult VmaDefragmentationAlgorithm_Generic::DefragmentRound(
    -
    14387  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    14388  VkDeviceSize maxBytesToMove,
    -
    14389  uint32_t maxAllocationsToMove,
    -
    14390  bool freeOldAllocations)
    -
    14391 {
    -
    14392  if(m_Blocks.empty())
    -
    14393  {
    -
    14394  return VK_SUCCESS;
    -
    14395  }
    +
    14328  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
    +
    14329 
    +
    14330  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    +
    14331  {
    +
    14332  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
    +
    14333  VMA_ASSERT(pBlock);
    +
    14334  VMA_HEAVY_ASSERT(pBlock->Validate());
    +
    14335  VmaStatInfo allocationStatInfo;
    +
    14336  pBlock->m_pMetadata->CalcAllocationStatInfo(allocationStatInfo);
    +
    14337  VmaAddStatInfo(pStats->total, allocationStatInfo);
    +
    14338  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
    +
    14339  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
    +
    14340  }
    +
    14341 }
    +
    14342 
    +
    14344 // VmaDefragmentationAlgorithm_Generic members definition
    +
    14345 
    +
    14346 VmaDefragmentationAlgorithm_Generic::VmaDefragmentationAlgorithm_Generic(
    +
    14347  VmaAllocator hAllocator,
    +
    14348  VmaBlockVector* pBlockVector,
    +
    14349  uint32_t currentFrameIndex,
    +
    14350  bool overlappingMoveSupported) :
    +
    14351  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
    +
    14352  m_AllocationCount(0),
    +
    14353  m_AllAllocations(false),
    +
    14354  m_BytesMoved(0),
    +
    14355  m_AllocationsMoved(0),
    +
    14356  m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))
    +
    14357 {
    +
    14358  // Create block info for each block.
    +
    14359  const size_t blockCount = m_pBlockVector->m_Blocks.size();
    +
    14360  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    +
    14361  {
    +
    14362  BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks());
    +
    14363  pBlockInfo->m_OriginalBlockIndex = blockIndex;
    +
    14364  pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex];
    +
    14365  m_Blocks.push_back(pBlockInfo);
    +
    14366  }
    +
    14367 
    +
    14368  // Sort them by m_pBlock pointer value.
    +
    14369  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
    +
    14370 }
    +
    14371 
    +
    14372 VmaDefragmentationAlgorithm_Generic::~VmaDefragmentationAlgorithm_Generic()
    +
    14373 {
    +
    14374  for(size_t i = m_Blocks.size(); i--; )
    +
    14375  {
    +
    14376  vma_delete(m_hAllocator, m_Blocks[i]);
    +
    14377  }
    +
    14378 }
    +
    14379 
    +
    14380 void VmaDefragmentationAlgorithm_Generic::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
    +
    14381 {
    +
    14382  // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost.
    +
    14383  if(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
    +
    14384  {
    +
    14385  VmaDeviceMemoryBlock* pBlock = hAlloc->GetBlock();
    +
    14386  BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
    +
    14387  if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
    +
    14388  {
    +
    14389  AllocationInfo allocInfo = AllocationInfo(hAlloc, pChanged);
    +
    14390  (*it)->m_Allocations.push_back(allocInfo);
    +
    14391  }
    +
    14392  else
    +
    14393  {
    +
    14394  VMA_ASSERT(0);
    +
    14395  }
    14396 
    -
    14397  // This is a choice based on research.
    -
    14398  // Option 1:
    -
    14399  uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
    -
    14400  // Option 2:
    -
    14401  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT;
    -
    14402  // Option 3:
    -
    14403  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT;
    -
    14404 
    -
    14405  size_t srcBlockMinIndex = 0;
    -
    14406  // When FAST_ALGORITHM, move allocations from only last out of blocks that contain non-movable allocations.
    -
    14407  /*
    -
    14408  if(m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT)
    -
    14409  {
    -
    14410  const size_t blocksWithNonMovableCount = CalcBlocksWithNonMovableCount();
    -
    14411  if(blocksWithNonMovableCount > 0)
    -
    14412  {
    -
    14413  srcBlockMinIndex = blocksWithNonMovableCount - 1;
    -
    14414  }
    -
    14415  }
    -
    14416  */
    -
    14417 
    -
    14418  size_t srcBlockIndex = m_Blocks.size() - 1;
    -
    14419  size_t srcAllocIndex = SIZE_MAX;
    -
    14420  for(;;)
    -
    14421  {
    -
    14422  // 1. Find next allocation to move.
    -
    14423  // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
    -
    14424  // 1.2. Then start from last to first m_Allocations.
    -
    14425  while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
    -
    14426  {
    -
    14427  if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
    -
    14428  {
    -
    14429  // Finished: no more allocations to process.
    -
    14430  if(srcBlockIndex == srcBlockMinIndex)
    -
    14431  {
    -
    14432  return VK_SUCCESS;
    -
    14433  }
    -
    14434  else
    -
    14435  {
    -
    14436  --srcBlockIndex;
    -
    14437  srcAllocIndex = SIZE_MAX;
    -
    14438  }
    -
    14439  }
    -
    14440  else
    -
    14441  {
    -
    14442  srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
    -
    14443  }
    -
    14444  }
    -
    14445 
    -
    14446  BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
    -
    14447  AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
    -
    14448 
    -
    14449  const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
    -
    14450  const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
    -
    14451  const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
    -
    14452  const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
    -
    14453 
    -
    14454  // 2. Try to find new place for this allocation in preceding or current block.
    -
    14455  for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
    -
    14456  {
    -
    14457  BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
    -
    14458  VmaAllocationRequest dstAllocRequest;
    -
    14459  if(pDstBlockInfo->m_pBlock->m_pMetadata->CreateAllocationRequest(
    -
    14460  m_CurrentFrameIndex,
    -
    14461  m_pBlockVector->GetFrameInUseCount(),
    -
    14462  m_pBlockVector->GetBufferImageGranularity(),
    -
    14463  size,
    -
    14464  alignment,
    -
    14465  false, // upperAddress
    -
    14466  suballocType,
    -
    14467  false, // canMakeOtherLost
    -
    14468  strategy,
    -
    14469  &dstAllocRequest) &&
    -
    14470  MoveMakesSense(
    -
    14471  dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
    -
    14472  {
    -
    14473  VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0);
    -
    14474 
    -
    14475  // Reached limit on number of allocations or bytes to move.
    -
    14476  if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
    -
    14477  (m_BytesMoved + size > maxBytesToMove))
    -
    14478  {
    -
    14479  return VK_SUCCESS;
    -
    14480  }
    -
    14481 
    -
    14482  VmaDefragmentationMove move = {};
    -
    14483  move.srcBlockIndex = pSrcBlockInfo->m_OriginalBlockIndex;
    -
    14484  move.dstBlockIndex = pDstBlockInfo->m_OriginalBlockIndex;
    -
    14485  move.srcOffset = srcOffset;
    -
    14486  move.dstOffset = dstAllocRequest.offset;
    -
    14487  move.size = size;
    -
    14488  move.hAllocation = allocInfo.m_hAllocation;
    -
    14489  move.pSrcBlock = pSrcBlockInfo->m_pBlock;
    -
    14490  move.pDstBlock = pDstBlockInfo->m_pBlock;
    -
    14491 
    -
    14492  moves.push_back(move);
    -
    14493 
    -
    14494  pDstBlockInfo->m_pBlock->m_pMetadata->Alloc(
    -
    14495  dstAllocRequest,
    -
    14496  suballocType,
    -
    14497  size,
    -
    14498  allocInfo.m_hAllocation);
    -
    14499 
    -
    14500  if(freeOldAllocations)
    -
    14501  {
    -
    14502  pSrcBlockInfo->m_pBlock->m_pMetadata->FreeAtOffset(srcOffset);
    -
    14503  allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
    -
    14504  }
    -
    14505 
    -
    14506  if(allocInfo.m_pChanged != VMA_NULL)
    -
    14507  {
    -
    14508  *allocInfo.m_pChanged = VK_TRUE;
    -
    14509  }
    -
    14510 
    -
    14511  ++m_AllocationsMoved;
    -
    14512  m_BytesMoved += size;
    -
    14513 
    -
    14514  VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
    -
    14515 
    -
    14516  break;
    -
    14517  }
    -
    14518  }
    -
    14519 
    -
    14520  // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round.
    -
    14521 
    -
    14522  if(srcAllocIndex > 0)
    -
    14523  {
    -
    14524  --srcAllocIndex;
    -
    14525  }
    -
    14526  else
    -
    14527  {
    -
    14528  if(srcBlockIndex > 0)
    -
    14529  {
    -
    14530  --srcBlockIndex;
    -
    14531  srcAllocIndex = SIZE_MAX;
    +
    14397  ++m_AllocationCount;
    +
    14398  }
    +
    14399 }
    +
    14400 
    +
    14401 VkResult VmaDefragmentationAlgorithm_Generic::DefragmentRound(
    +
    14402  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    14403  VkDeviceSize maxBytesToMove,
    +
    14404  uint32_t maxAllocationsToMove,
    +
    14405  bool freeOldAllocations)
    +
    14406 {
    +
    14407  if(m_Blocks.empty())
    +
    14408  {
    +
    14409  return VK_SUCCESS;
    +
    14410  }
    +
    14411 
    +
    14412  // This is a choice based on research.
    +
    14413  // Option 1:
    +
    14414  uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
    +
    14415  // Option 2:
    +
    14416  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT;
    +
    14417  // Option 3:
    +
    14418  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT;
    +
    14419 
    +
    14420  size_t srcBlockMinIndex = 0;
    +
    14421  // When FAST_ALGORITHM, move allocations from only last out of blocks that contain non-movable allocations.
    +
    14422  /*
    +
    14423  if(m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT)
    +
    14424  {
    +
    14425  const size_t blocksWithNonMovableCount = CalcBlocksWithNonMovableCount();
    +
    14426  if(blocksWithNonMovableCount > 0)
    +
    14427  {
    +
    14428  srcBlockMinIndex = blocksWithNonMovableCount - 1;
    +
    14429  }
    +
    14430  }
    +
    14431  */
    +
    14432 
    +
    14433  size_t srcBlockIndex = m_Blocks.size() - 1;
    +
    14434  size_t srcAllocIndex = SIZE_MAX;
    +
    14435  for(;;)
    +
    14436  {
    +
    14437  // 1. Find next allocation to move.
    +
    14438  // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
    +
    14439  // 1.2. Then start from last to first m_Allocations.
    +
    14440  while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
    +
    14441  {
    +
    14442  if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
    +
    14443  {
    +
    14444  // Finished: no more allocations to process.
    +
    14445  if(srcBlockIndex == srcBlockMinIndex)
    +
    14446  {
    +
    14447  return VK_SUCCESS;
    +
    14448  }
    +
    14449  else
    +
    14450  {
    +
    14451  --srcBlockIndex;
    +
    14452  srcAllocIndex = SIZE_MAX;
    +
    14453  }
    +
    14454  }
    +
    14455  else
    +
    14456  {
    +
    14457  srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
    +
    14458  }
    +
    14459  }
    +
    14460 
    +
    14461  BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
    +
    14462  AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
    +
    14463 
    +
    14464  const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
    +
    14465  const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
    +
    14466  const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
    +
    14467  const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
    +
    14468 
    +
    14469  // 2. Try to find new place for this allocation in preceding or current block.
    +
    14470  for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
    +
    14471  {
    +
    14472  BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
    +
    14473  VmaAllocationRequest dstAllocRequest;
    +
    14474  if(pDstBlockInfo->m_pBlock->m_pMetadata->CreateAllocationRequest(
    +
    14475  m_CurrentFrameIndex,
    +
    14476  m_pBlockVector->GetFrameInUseCount(),
    +
    14477  m_pBlockVector->GetBufferImageGranularity(),
    +
    14478  size,
    +
    14479  alignment,
    +
    14480  false, // upperAddress
    +
    14481  suballocType,
    +
    14482  false, // canMakeOtherLost
    +
    14483  strategy,
    +
    14484  &dstAllocRequest) &&
    +
    14485  MoveMakesSense(
    +
    14486  dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
    +
    14487  {
    +
    14488  VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0);
    +
    14489 
    +
    14490  // Reached limit on number of allocations or bytes to move.
    +
    14491  if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
    +
    14492  (m_BytesMoved + size > maxBytesToMove))
    +
    14493  {
    +
    14494  return VK_SUCCESS;
    +
    14495  }
    +
    14496 
    +
    14497  VmaDefragmentationMove move = {};
    +
    14498  move.srcBlockIndex = pSrcBlockInfo->m_OriginalBlockIndex;
    +
    14499  move.dstBlockIndex = pDstBlockInfo->m_OriginalBlockIndex;
    +
    14500  move.srcOffset = srcOffset;
    +
    14501  move.dstOffset = dstAllocRequest.offset;
    +
    14502  move.size = size;
    +
    14503  move.hAllocation = allocInfo.m_hAllocation;
    +
    14504  move.pSrcBlock = pSrcBlockInfo->m_pBlock;
    +
    14505  move.pDstBlock = pDstBlockInfo->m_pBlock;
    +
    14506 
    +
    14507  moves.push_back(move);
    +
    14508 
    +
    14509  pDstBlockInfo->m_pBlock->m_pMetadata->Alloc(
    +
    14510  dstAllocRequest,
    +
    14511  suballocType,
    +
    14512  size,
    +
    14513  allocInfo.m_hAllocation);
    +
    14514 
    +
    14515  if(freeOldAllocations)
    +
    14516  {
    +
    14517  pSrcBlockInfo->m_pBlock->m_pMetadata->FreeAtOffset(srcOffset);
    +
    14518  allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
    +
    14519  }
    +
    14520 
    +
    14521  if(allocInfo.m_pChanged != VMA_NULL)
    +
    14522  {
    +
    14523  *allocInfo.m_pChanged = VK_TRUE;
    +
    14524  }
    +
    14525 
    +
    14526  ++m_AllocationsMoved;
    +
    14527  m_BytesMoved += size;
    +
    14528 
    +
    14529  VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
    +
    14530 
    +
    14531  break;
    14532  }
    -
    14533  else
    -
    14534  {
    -
    14535  return VK_SUCCESS;
    -
    14536  }
    -
    14537  }
    -
    14538  }
    -
    14539 }
    -
    14540 
    -
    14541 size_t VmaDefragmentationAlgorithm_Generic::CalcBlocksWithNonMovableCount() const
    -
    14542 {
    -
    14543  size_t result = 0;
    -
    14544  for(size_t i = 0; i < m_Blocks.size(); ++i)
    -
    14545  {
    -
    14546  if(m_Blocks[i]->m_HasNonMovableAllocations)
    -
    14547  {
    -
    14548  ++result;
    -
    14549  }
    -
    14550  }
    -
    14551  return result;
    -
    14552 }
    -
    14553 
    -
    14554 VkResult VmaDefragmentationAlgorithm_Generic::Defragment(
    -
    14555  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    14556  VkDeviceSize maxBytesToMove,
    -
    14557  uint32_t maxAllocationsToMove,
    -
    14558  VmaDefragmentationFlags flags)
    -
    14559 {
    -
    14560  if(!m_AllAllocations && m_AllocationCount == 0)
    -
    14561  {
    -
    14562  return VK_SUCCESS;
    -
    14563  }
    -
    14564 
    -
    14565  const size_t blockCount = m_Blocks.size();
    -
    14566  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    -
    14567  {
    -
    14568  BlockInfo* pBlockInfo = m_Blocks[blockIndex];
    -
    14569 
    -
    14570  if(m_AllAllocations)
    -
    14571  {
    -
    14572  VmaBlockMetadata_Generic* pMetadata = (VmaBlockMetadata_Generic*)pBlockInfo->m_pBlock->m_pMetadata;
    -
    14573  for(VmaSuballocationList::const_iterator it = pMetadata->m_Suballocations.begin();
    -
    14574  it != pMetadata->m_Suballocations.end();
    -
    14575  ++it)
    -
    14576  {
    -
    14577  if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
    -
    14578  {
    -
    14579  AllocationInfo allocInfo = AllocationInfo(it->hAllocation, VMA_NULL);
    -
    14580  pBlockInfo->m_Allocations.push_back(allocInfo);
    -
    14581  }
    -
    14582  }
    -
    14583  }
    +
    14533  }
    +
    14534 
    +
    14535  // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round.
    +
    14536 
    +
    14537  if(srcAllocIndex > 0)
    +
    14538  {
    +
    14539  --srcAllocIndex;
    +
    14540  }
    +
    14541  else
    +
    14542  {
    +
    14543  if(srcBlockIndex > 0)
    +
    14544  {
    +
    14545  --srcBlockIndex;
    +
    14546  srcAllocIndex = SIZE_MAX;
    +
    14547  }
    +
    14548  else
    +
    14549  {
    +
    14550  return VK_SUCCESS;
    +
    14551  }
    +
    14552  }
    +
    14553  }
    +
    14554 }
    +
    14555 
    +
    14556 size_t VmaDefragmentationAlgorithm_Generic::CalcBlocksWithNonMovableCount() const
    +
    14557 {
    +
    14558  size_t result = 0;
    +
    14559  for(size_t i = 0; i < m_Blocks.size(); ++i)
    +
    14560  {
    +
    14561  if(m_Blocks[i]->m_HasNonMovableAllocations)
    +
    14562  {
    +
    14563  ++result;
    +
    14564  }
    +
    14565  }
    +
    14566  return result;
    +
    14567 }
    +
    14568 
    +
    14569 VkResult VmaDefragmentationAlgorithm_Generic::Defragment(
    +
    14570  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    14571  VkDeviceSize maxBytesToMove,
    +
    14572  uint32_t maxAllocationsToMove,
    +
    14573  VmaDefragmentationFlags flags)
    +
    14574 {
    +
    14575  if(!m_AllAllocations && m_AllocationCount == 0)
    +
    14576  {
    +
    14577  return VK_SUCCESS;
    +
    14578  }
    +
    14579 
    +
    14580  const size_t blockCount = m_Blocks.size();
    +
    14581  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    +
    14582  {
    +
    14583  BlockInfo* pBlockInfo = m_Blocks[blockIndex];
    14584 
    -
    14585  pBlockInfo->CalcHasNonMovableAllocations();
    -
    14586 
    -
    14587  // This is a choice based on research.
    -
    14588  // Option 1:
    -
    14589  pBlockInfo->SortAllocationsByOffsetDescending();
    -
    14590  // Option 2:
    -
    14591  //pBlockInfo->SortAllocationsBySizeDescending();
    -
    14592  }
    -
    14593 
    -
    14594  // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
    -
    14595  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
    -
    14596 
    -
    14597  // This is a choice based on research.
    -
    14598  const uint32_t roundCount = 2;
    +
    14585  if(m_AllAllocations)
    +
    14586  {
    +
    14587  VmaBlockMetadata_Generic* pMetadata = (VmaBlockMetadata_Generic*)pBlockInfo->m_pBlock->m_pMetadata;
    +
    14588  for(VmaSuballocationList::const_iterator it = pMetadata->m_Suballocations.begin();
    +
    14589  it != pMetadata->m_Suballocations.end();
    +
    14590  ++it)
    +
    14591  {
    +
    14592  if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
    +
    14593  {
    +
    14594  AllocationInfo allocInfo = AllocationInfo(it->hAllocation, VMA_NULL);
    +
    14595  pBlockInfo->m_Allocations.push_back(allocInfo);
    +
    14596  }
    +
    14597  }
    +
    14598  }
    14599 
    -
    14600  // Execute defragmentation rounds (the main part).
    -
    14601  VkResult result = VK_SUCCESS;
    -
    14602  for(uint32_t round = 0; (round < roundCount) && (result == VK_SUCCESS); ++round)
    -
    14603  {
    -
    14604  result = DefragmentRound(moves, maxBytesToMove, maxAllocationsToMove, !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL));
    -
    14605  }
    -
    14606 
    -
    14607  return result;
    -
    14608 }
    -
    14609 
    -
    14610 bool VmaDefragmentationAlgorithm_Generic::MoveMakesSense(
    -
    14611  size_t dstBlockIndex, VkDeviceSize dstOffset,
    -
    14612  size_t srcBlockIndex, VkDeviceSize srcOffset)
    -
    14613 {
    -
    14614  if(dstBlockIndex < srcBlockIndex)
    -
    14615  {
    -
    14616  return true;
    -
    14617  }
    -
    14618  if(dstBlockIndex > srcBlockIndex)
    -
    14619  {
    -
    14620  return false;
    -
    14621  }
    -
    14622  if(dstOffset < srcOffset)
    -
    14623  {
    -
    14624  return true;
    -
    14625  }
    -
    14626  return false;
    -
    14627 }
    -
    14628 
    -
    14630 // VmaDefragmentationAlgorithm_Fast
    -
    14631 
    -
    14632 VmaDefragmentationAlgorithm_Fast::VmaDefragmentationAlgorithm_Fast(
    -
    14633  VmaAllocator hAllocator,
    -
    14634  VmaBlockVector* pBlockVector,
    -
    14635  uint32_t currentFrameIndex,
    -
    14636  bool overlappingMoveSupported) :
    -
    14637  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
    -
    14638  m_OverlappingMoveSupported(overlappingMoveSupported),
    -
    14639  m_AllocationCount(0),
    -
    14640  m_AllAllocations(false),
    -
    14641  m_BytesMoved(0),
    -
    14642  m_AllocationsMoved(0),
    -
    14643  m_BlockInfos(VmaStlAllocator<BlockInfo>(hAllocator->GetAllocationCallbacks()))
    -
    14644 {
    -
    14645  VMA_ASSERT(VMA_DEBUG_MARGIN == 0);
    +
    14600  pBlockInfo->CalcHasNonMovableAllocations();
    +
    14601 
    +
    14602  // This is a choice based on research.
    +
    14603  // Option 1:
    +
    14604  pBlockInfo->SortAllocationsByOffsetDescending();
    +
    14605  // Option 2:
    +
    14606  //pBlockInfo->SortAllocationsBySizeDescending();
    +
    14607  }
    +
    14608 
    +
    14609  // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
    +
    14610  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
    +
    14611 
    +
    14612  // This is a choice based on research.
    +
    14613  const uint32_t roundCount = 2;
    +
    14614 
    +
    14615  // Execute defragmentation rounds (the main part).
    +
    14616  VkResult result = VK_SUCCESS;
    +
    14617  for(uint32_t round = 0; (round < roundCount) && (result == VK_SUCCESS); ++round)
    +
    14618  {
    +
    14619  result = DefragmentRound(moves, maxBytesToMove, maxAllocationsToMove, !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL));
    +
    14620  }
    +
    14621 
    +
    14622  return result;
    +
    14623 }
    +
    14624 
    +
    14625 bool VmaDefragmentationAlgorithm_Generic::MoveMakesSense(
    +
    14626  size_t dstBlockIndex, VkDeviceSize dstOffset,
    +
    14627  size_t srcBlockIndex, VkDeviceSize srcOffset)
    +
    14628 {
    +
    14629  if(dstBlockIndex < srcBlockIndex)
    +
    14630  {
    +
    14631  return true;
    +
    14632  }
    +
    14633  if(dstBlockIndex > srcBlockIndex)
    +
    14634  {
    +
    14635  return false;
    +
    14636  }
    +
    14637  if(dstOffset < srcOffset)
    +
    14638  {
    +
    14639  return true;
    +
    14640  }
    +
    14641  return false;
    +
    14642 }
    +
    14643 
    +
    14645 // VmaDefragmentationAlgorithm_Fast
    14646 
    -
    14647 }
    -
    14648 
    -
    14649 VmaDefragmentationAlgorithm_Fast::~VmaDefragmentationAlgorithm_Fast()
    -
    14650 {
    -
    14651 }
    -
    14652 
    -
    14653 VkResult VmaDefragmentationAlgorithm_Fast::Defragment(
    -
    14654  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    -
    14655  VkDeviceSize maxBytesToMove,
    -
    14656  uint32_t maxAllocationsToMove,
    -
    14657  VmaDefragmentationFlags flags)
    -
    14658 {
    -
    14659  VMA_ASSERT(m_AllAllocations || m_pBlockVector->CalcAllocationCount() == m_AllocationCount);
    -
    14660 
    -
    14661  const size_t blockCount = m_pBlockVector->GetBlockCount();
    -
    14662  if(blockCount == 0 || maxBytesToMove == 0 || maxAllocationsToMove == 0)
    -
    14663  {
    -
    14664  return VK_SUCCESS;
    -
    14665  }
    -
    14666 
    -
    14667  PreprocessMetadata();
    -
    14668 
    -
    14669  // Sort blocks in order from most destination.
    -
    14670 
    -
    14671  m_BlockInfos.resize(blockCount);
    -
    14672  for(size_t i = 0; i < blockCount; ++i)
    -
    14673  {
    -
    14674  m_BlockInfos[i].origBlockIndex = i;
    -
    14675  }
    -
    14676 
    -
    14677  VMA_SORT(m_BlockInfos.begin(), m_BlockInfos.end(), [this](const BlockInfo& lhs, const BlockInfo& rhs) -> bool {
    -
    14678  return m_pBlockVector->GetBlock(lhs.origBlockIndex)->m_pMetadata->GetSumFreeSize() <
    -
    14679  m_pBlockVector->GetBlock(rhs.origBlockIndex)->m_pMetadata->GetSumFreeSize();
    -
    14680  });
    +
    14647 VmaDefragmentationAlgorithm_Fast::VmaDefragmentationAlgorithm_Fast(
    +
    14648  VmaAllocator hAllocator,
    +
    14649  VmaBlockVector* pBlockVector,
    +
    14650  uint32_t currentFrameIndex,
    +
    14651  bool overlappingMoveSupported) :
    +
    14652  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
    +
    14653  m_OverlappingMoveSupported(overlappingMoveSupported),
    +
    14654  m_AllocationCount(0),
    +
    14655  m_AllAllocations(false),
    +
    14656  m_BytesMoved(0),
    +
    14657  m_AllocationsMoved(0),
    +
    14658  m_BlockInfos(VmaStlAllocator<BlockInfo>(hAllocator->GetAllocationCallbacks()))
    +
    14659 {
    +
    14660  VMA_ASSERT(VMA_DEBUG_MARGIN == 0);
    +
    14661 
    +
    14662 }
    +
    14663 
    +
    14664 VmaDefragmentationAlgorithm_Fast::~VmaDefragmentationAlgorithm_Fast()
    +
    14665 {
    +
    14666 }
    +
    14667 
    +
    14668 VkResult VmaDefragmentationAlgorithm_Fast::Defragment(
    +
    14669  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
    +
    14670  VkDeviceSize maxBytesToMove,
    +
    14671  uint32_t maxAllocationsToMove,
    +
    14672  VmaDefragmentationFlags flags)
    +
    14673 {
    +
    14674  VMA_ASSERT(m_AllAllocations || m_pBlockVector->CalcAllocationCount() == m_AllocationCount);
    +
    14675 
    +
    14676  const size_t blockCount = m_pBlockVector->GetBlockCount();
    +
    14677  if(blockCount == 0 || maxBytesToMove == 0 || maxAllocationsToMove == 0)
    +
    14678  {
    +
    14679  return VK_SUCCESS;
    +
    14680  }
    14681 
    -
    14682  // THE MAIN ALGORITHM
    +
    14682  PreprocessMetadata();
    14683 
    -
    14684  FreeSpaceDatabase freeSpaceDb;
    +
    14684  // Sort blocks in order from most destination.
    14685 
    -
    14686  size_t dstBlockInfoIndex = 0;
    -
    14687  size_t dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
    -
    14688  VmaDeviceMemoryBlock* pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
    -
    14689  VmaBlockMetadata_Generic* pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
    -
    14690  VkDeviceSize dstBlockSize = pDstMetadata->GetSize();
    -
    14691  VkDeviceSize dstOffset = 0;
    -
    14692 
    -
    14693  bool end = false;
    -
    14694  for(size_t srcBlockInfoIndex = 0; !end && srcBlockInfoIndex < blockCount; ++srcBlockInfoIndex)
    -
    14695  {
    -
    14696  const size_t srcOrigBlockIndex = m_BlockInfos[srcBlockInfoIndex].origBlockIndex;
    -
    14697  VmaDeviceMemoryBlock* const pSrcBlock = m_pBlockVector->GetBlock(srcOrigBlockIndex);
    -
    14698  VmaBlockMetadata_Generic* const pSrcMetadata = (VmaBlockMetadata_Generic*)pSrcBlock->m_pMetadata;
    -
    14699  for(VmaSuballocationList::iterator srcSuballocIt = pSrcMetadata->m_Suballocations.begin();
    -
    14700  !end && srcSuballocIt != pSrcMetadata->m_Suballocations.end(); )
    -
    14701  {
    -
    14702  VmaAllocation_T* const pAlloc = srcSuballocIt->hAllocation;
    -
    14703  const VkDeviceSize srcAllocAlignment = pAlloc->GetAlignment();
    -
    14704  const VkDeviceSize srcAllocSize = srcSuballocIt->size;
    -
    14705  if(m_AllocationsMoved == maxAllocationsToMove ||
    -
    14706  m_BytesMoved + srcAllocSize > maxBytesToMove)
    -
    14707  {
    -
    14708  end = true;
    -
    14709  break;
    -
    14710  }
    -
    14711  const VkDeviceSize srcAllocOffset = srcSuballocIt->offset;
    -
    14712 
    -
    14713  VmaDefragmentationMove move = {};
    -
    14714  // Try to place it in one of free spaces from the database.
    -
    14715  size_t freeSpaceInfoIndex;
    -
    14716  VkDeviceSize dstAllocOffset;
    -
    14717  if(freeSpaceDb.Fetch(srcAllocAlignment, srcAllocSize,
    -
    14718  freeSpaceInfoIndex, dstAllocOffset))
    -
    14719  {
    -
    14720  size_t freeSpaceOrigBlockIndex = m_BlockInfos[freeSpaceInfoIndex].origBlockIndex;
    -
    14721  VmaDeviceMemoryBlock* pFreeSpaceBlock = m_pBlockVector->GetBlock(freeSpaceOrigBlockIndex);
    -
    14722  VmaBlockMetadata_Generic* pFreeSpaceMetadata = (VmaBlockMetadata_Generic*)pFreeSpaceBlock->m_pMetadata;
    -
    14723 
    -
    14724  // Same block
    -
    14725  if(freeSpaceInfoIndex == srcBlockInfoIndex)
    -
    14726  {
    -
    14727  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
    -
    14728 
    -
    14729  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
    -
    14730 
    -
    14731  VmaSuballocation suballoc = *srcSuballocIt;
    -
    14732  suballoc.offset = dstAllocOffset;
    -
    14733  suballoc.hAllocation->ChangeOffset(dstAllocOffset);
    -
    14734  m_BytesMoved += srcAllocSize;
    -
    14735  ++m_AllocationsMoved;
    -
    14736 
    -
    14737  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
    -
    14738  ++nextSuballocIt;
    -
    14739  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
    -
    14740  srcSuballocIt = nextSuballocIt;
    -
    14741 
    -
    14742  InsertSuballoc(pFreeSpaceMetadata, suballoc);
    +
    14686  m_BlockInfos.resize(blockCount);
    +
    14687  for(size_t i = 0; i < blockCount; ++i)
    +
    14688  {
    +
    14689  m_BlockInfos[i].origBlockIndex = i;
    +
    14690  }
    +
    14691 
    +
    14692  VMA_SORT(m_BlockInfos.begin(), m_BlockInfos.end(), [this](const BlockInfo& lhs, const BlockInfo& rhs) -> bool {
    +
    14693  return m_pBlockVector->GetBlock(lhs.origBlockIndex)->m_pMetadata->GetSumFreeSize() <
    +
    14694  m_pBlockVector->GetBlock(rhs.origBlockIndex)->m_pMetadata->GetSumFreeSize();
    +
    14695  });
    +
    14696 
    +
    14697  // THE MAIN ALGORITHM
    +
    14698 
    +
    14699  FreeSpaceDatabase freeSpaceDb;
    +
    14700 
    +
    14701  size_t dstBlockInfoIndex = 0;
    +
    14702  size_t dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
    +
    14703  VmaDeviceMemoryBlock* pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
    +
    14704  VmaBlockMetadata_Generic* pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
    +
    14705  VkDeviceSize dstBlockSize = pDstMetadata->GetSize();
    +
    14706  VkDeviceSize dstOffset = 0;
    +
    14707 
    +
    14708  bool end = false;
    +
    14709  for(size_t srcBlockInfoIndex = 0; !end && srcBlockInfoIndex < blockCount; ++srcBlockInfoIndex)
    +
    14710  {
    +
    14711  const size_t srcOrigBlockIndex = m_BlockInfos[srcBlockInfoIndex].origBlockIndex;
    +
    14712  VmaDeviceMemoryBlock* const pSrcBlock = m_pBlockVector->GetBlock(srcOrigBlockIndex);
    +
    14713  VmaBlockMetadata_Generic* const pSrcMetadata = (VmaBlockMetadata_Generic*)pSrcBlock->m_pMetadata;
    +
    14714  for(VmaSuballocationList::iterator srcSuballocIt = pSrcMetadata->m_Suballocations.begin();
    +
    14715  !end && srcSuballocIt != pSrcMetadata->m_Suballocations.end(); )
    +
    14716  {
    +
    14717  VmaAllocation_T* const pAlloc = srcSuballocIt->hAllocation;
    +
    14718  const VkDeviceSize srcAllocAlignment = pAlloc->GetAlignment();
    +
    14719  const VkDeviceSize srcAllocSize = srcSuballocIt->size;
    +
    14720  if(m_AllocationsMoved == maxAllocationsToMove ||
    +
    14721  m_BytesMoved + srcAllocSize > maxBytesToMove)
    +
    14722  {
    +
    14723  end = true;
    +
    14724  break;
    +
    14725  }
    +
    14726  const VkDeviceSize srcAllocOffset = srcSuballocIt->offset;
    +
    14727 
    +
    14728  VmaDefragmentationMove move = {};
    +
    14729  // Try to place it in one of free spaces from the database.
    +
    14730  size_t freeSpaceInfoIndex;
    +
    14731  VkDeviceSize dstAllocOffset;
    +
    14732  if(freeSpaceDb.Fetch(srcAllocAlignment, srcAllocSize,
    +
    14733  freeSpaceInfoIndex, dstAllocOffset))
    +
    14734  {
    +
    14735  size_t freeSpaceOrigBlockIndex = m_BlockInfos[freeSpaceInfoIndex].origBlockIndex;
    +
    14736  VmaDeviceMemoryBlock* pFreeSpaceBlock = m_pBlockVector->GetBlock(freeSpaceOrigBlockIndex);
    +
    14737  VmaBlockMetadata_Generic* pFreeSpaceMetadata = (VmaBlockMetadata_Generic*)pFreeSpaceBlock->m_pMetadata;
    +
    14738 
    +
    14739  // Same block
    +
    14740  if(freeSpaceInfoIndex == srcBlockInfoIndex)
    +
    14741  {
    +
    14742  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
    14743 
    -
    14744  move.srcBlockIndex = srcOrigBlockIndex;
    -
    14745  move.dstBlockIndex = freeSpaceOrigBlockIndex;
    -
    14746  move.srcOffset = srcAllocOffset;
    -
    14747  move.dstOffset = dstAllocOffset;
    -
    14748  move.size = srcAllocSize;
    -
    14749 
    -
    14750  moves.push_back(move);
    -
    14751  }
    -
    14752  // Different block
    -
    14753  else
    -
    14754  {
    -
    14755  // MOVE OPTION 2: Move the allocation to a different block.
    +
    14744  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
    +
    14745 
    +
    14746  VmaSuballocation suballoc = *srcSuballocIt;
    +
    14747  suballoc.offset = dstAllocOffset;
    +
    14748  suballoc.hAllocation->ChangeOffset(dstAllocOffset);
    +
    14749  m_BytesMoved += srcAllocSize;
    +
    14750  ++m_AllocationsMoved;
    +
    14751 
    +
    14752  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
    +
    14753  ++nextSuballocIt;
    +
    14754  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
    +
    14755  srcSuballocIt = nextSuballocIt;
    14756 
    -
    14757  VMA_ASSERT(freeSpaceInfoIndex < srcBlockInfoIndex);
    +
    14757  InsertSuballoc(pFreeSpaceMetadata, suballoc);
    14758 
    -
    14759  VmaSuballocation suballoc = *srcSuballocIt;
    -
    14760  suballoc.offset = dstAllocOffset;
    -
    14761  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pFreeSpaceBlock, dstAllocOffset);
    -
    14762  m_BytesMoved += srcAllocSize;
    -
    14763  ++m_AllocationsMoved;
    +
    14759  move.srcBlockIndex = srcOrigBlockIndex;
    +
    14760  move.dstBlockIndex = freeSpaceOrigBlockIndex;
    +
    14761  move.srcOffset = srcAllocOffset;
    +
    14762  move.dstOffset = dstAllocOffset;
    +
    14763  move.size = srcAllocSize;
    14764 
    -
    14765  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
    -
    14766  ++nextSuballocIt;
    -
    14767  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
    -
    14768  srcSuballocIt = nextSuballocIt;
    -
    14769 
    -
    14770  InsertSuballoc(pFreeSpaceMetadata, suballoc);
    +
    14765  moves.push_back(move);
    +
    14766  }
    +
    14767  // Different block
    +
    14768  else
    +
    14769  {
    +
    14770  // MOVE OPTION 2: Move the allocation to a different block.
    14771 
    -
    14772  move.srcBlockIndex = srcOrigBlockIndex;
    -
    14773  move.dstBlockIndex = freeSpaceOrigBlockIndex;
    -
    14774  move.srcOffset = srcAllocOffset;
    -
    14775  move.dstOffset = dstAllocOffset;
    -
    14776  move.size = srcAllocSize;
    -
    14777 
    -
    14778  moves.push_back(move);
    -
    14779  }
    -
    14780  }
    -
    14781  else
    -
    14782  {
    -
    14783  dstAllocOffset = VmaAlignUp(dstOffset, srcAllocAlignment);
    +
    14772  VMA_ASSERT(freeSpaceInfoIndex < srcBlockInfoIndex);
    +
    14773 
    +
    14774  VmaSuballocation suballoc = *srcSuballocIt;
    +
    14775  suballoc.offset = dstAllocOffset;
    +
    14776  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pFreeSpaceBlock, dstAllocOffset);
    +
    14777  m_BytesMoved += srcAllocSize;
    +
    14778  ++m_AllocationsMoved;
    +
    14779 
    +
    14780  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
    +
    14781  ++nextSuballocIt;
    +
    14782  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
    +
    14783  srcSuballocIt = nextSuballocIt;
    14784 
    -
    14785  // If the allocation doesn't fit before the end of dstBlock, forward to next block.
    -
    14786  while(dstBlockInfoIndex < srcBlockInfoIndex &&
    -
    14787  dstAllocOffset + srcAllocSize > dstBlockSize)
    -
    14788  {
    -
    14789  // But before that, register remaining free space at the end of dst block.
    -
    14790  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, dstBlockSize - dstOffset);
    -
    14791 
    -
    14792  ++dstBlockInfoIndex;
    -
    14793  dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
    -
    14794  pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
    -
    14795  pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
    -
    14796  dstBlockSize = pDstMetadata->GetSize();
    -
    14797  dstOffset = 0;
    -
    14798  dstAllocOffset = 0;
    -
    14799  }
    -
    14800 
    -
    14801  // Same block
    -
    14802  if(dstBlockInfoIndex == srcBlockInfoIndex)
    +
    14785  InsertSuballoc(pFreeSpaceMetadata, suballoc);
    +
    14786 
    +
    14787  move.srcBlockIndex = srcOrigBlockIndex;
    +
    14788  move.dstBlockIndex = freeSpaceOrigBlockIndex;
    +
    14789  move.srcOffset = srcAllocOffset;
    +
    14790  move.dstOffset = dstAllocOffset;
    +
    14791  move.size = srcAllocSize;
    +
    14792 
    +
    14793  moves.push_back(move);
    +
    14794  }
    +
    14795  }
    +
    14796  else
    +
    14797  {
    +
    14798  dstAllocOffset = VmaAlignUp(dstOffset, srcAllocAlignment);
    +
    14799 
    +
    14800  // If the allocation doesn't fit before the end of dstBlock, forward to next block.
    +
    14801  while(dstBlockInfoIndex < srcBlockInfoIndex &&
    +
    14802  dstAllocOffset + srcAllocSize > dstBlockSize)
    14803  {
    -
    14804  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
    -
    14805 
    -
    14806  const bool overlap = dstAllocOffset + srcAllocSize > srcAllocOffset;
    -
    14807 
    -
    14808  bool skipOver = overlap;
    -
    14809  if(overlap && m_OverlappingMoveSupported && dstAllocOffset < srcAllocOffset)
    -
    14810  {
    -
    14811  // If destination and source place overlap, skip if it would move it
    -
    14812  // by only < 1/64 of its size.
    -
    14813  skipOver = (srcAllocOffset - dstAllocOffset) * 64 < srcAllocSize;
    -
    14814  }
    +
    14804  // But before that, register remaining free space at the end of dst block.
    +
    14805  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, dstBlockSize - dstOffset);
    +
    14806 
    +
    14807  ++dstBlockInfoIndex;
    +
    14808  dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
    +
    14809  pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
    +
    14810  pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
    +
    14811  dstBlockSize = pDstMetadata->GetSize();
    +
    14812  dstOffset = 0;
    +
    14813  dstAllocOffset = 0;
    +
    14814  }
    14815 
    -
    14816  if(skipOver)
    -
    14817  {
    -
    14818  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, srcAllocOffset - dstOffset);
    -
    14819 
    -
    14820  dstOffset = srcAllocOffset + srcAllocSize;
    -
    14821  ++srcSuballocIt;
    -
    14822  }
    -
    14823  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
    -
    14824  else
    +
    14816  // Same block
    +
    14817  if(dstBlockInfoIndex == srcBlockInfoIndex)
    +
    14818  {
    +
    14819  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
    +
    14820 
    +
    14821  const bool overlap = dstAllocOffset + srcAllocSize > srcAllocOffset;
    +
    14822 
    +
    14823  bool skipOver = overlap;
    +
    14824  if(overlap && m_OverlappingMoveSupported && dstAllocOffset < srcAllocOffset)
    14825  {
    -
    14826  srcSuballocIt->offset = dstAllocOffset;
    -
    14827  srcSuballocIt->hAllocation->ChangeOffset(dstAllocOffset);
    -
    14828  dstOffset = dstAllocOffset + srcAllocSize;
    -
    14829  m_BytesMoved += srcAllocSize;
    -
    14830  ++m_AllocationsMoved;
    -
    14831  ++srcSuballocIt;
    -
    14832 
    -
    14833  move.srcBlockIndex = srcOrigBlockIndex;
    -
    14834  move.dstBlockIndex = dstOrigBlockIndex;
    -
    14835  move.srcOffset = srcAllocOffset;
    -
    14836  move.dstOffset = dstAllocOffset;
    -
    14837  move.size = srcAllocSize;
    -
    14838 
    -
    14839  moves.push_back(move);
    -
    14840  }
    -
    14841  }
    -
    14842  // Different block
    -
    14843  else
    -
    14844  {
    -
    14845  // MOVE OPTION 2: Move the allocation to a different block.
    -
    14846 
    -
    14847  VMA_ASSERT(dstBlockInfoIndex < srcBlockInfoIndex);
    -
    14848  VMA_ASSERT(dstAllocOffset + srcAllocSize <= dstBlockSize);
    -
    14849 
    -
    14850  VmaSuballocation suballoc = *srcSuballocIt;
    -
    14851  suballoc.offset = dstAllocOffset;
    -
    14852  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlock, dstAllocOffset);
    -
    14853  dstOffset = dstAllocOffset + srcAllocSize;
    -
    14854  m_BytesMoved += srcAllocSize;
    -
    14855  ++m_AllocationsMoved;
    -
    14856 
    -
    14857  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
    -
    14858  ++nextSuballocIt;
    -
    14859  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
    -
    14860  srcSuballocIt = nextSuballocIt;
    +
    14826  // If destination and source place overlap, skip if it would move it
    +
    14827  // by only < 1/64 of its size.
    +
    14828  skipOver = (srcAllocOffset - dstAllocOffset) * 64 < srcAllocSize;
    +
    14829  }
    +
    14830 
    +
    14831  if(skipOver)
    +
    14832  {
    +
    14833  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, srcAllocOffset - dstOffset);
    +
    14834 
    +
    14835  dstOffset = srcAllocOffset + srcAllocSize;
    +
    14836  ++srcSuballocIt;
    +
    14837  }
    +
    14838  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
    +
    14839  else
    +
    14840  {
    +
    14841  srcSuballocIt->offset = dstAllocOffset;
    +
    14842  srcSuballocIt->hAllocation->ChangeOffset(dstAllocOffset);
    +
    14843  dstOffset = dstAllocOffset + srcAllocSize;
    +
    14844  m_BytesMoved += srcAllocSize;
    +
    14845  ++m_AllocationsMoved;
    +
    14846  ++srcSuballocIt;
    +
    14847 
    +
    14848  move.srcBlockIndex = srcOrigBlockIndex;
    +
    14849  move.dstBlockIndex = dstOrigBlockIndex;
    +
    14850  move.srcOffset = srcAllocOffset;
    +
    14851  move.dstOffset = dstAllocOffset;
    +
    14852  move.size = srcAllocSize;
    +
    14853 
    +
    14854  moves.push_back(move);
    +
    14855  }
    +
    14856  }
    +
    14857  // Different block
    +
    14858  else
    +
    14859  {
    +
    14860  // MOVE OPTION 2: Move the allocation to a different block.
    14861 
    -
    14862  pDstMetadata->m_Suballocations.push_back(suballoc);
    -
    14863 
    -
    14864  move.srcBlockIndex = srcOrigBlockIndex;
    -
    14865  move.dstBlockIndex = dstOrigBlockIndex;
    -
    14866  move.srcOffset = srcAllocOffset;
    -
    14867  move.dstOffset = dstAllocOffset;
    -
    14868  move.size = srcAllocSize;
    -
    14869 
    -
    14870  moves.push_back(move);
    -
    14871  }
    -
    14872  }
    -
    14873  }
    -
    14874  }
    -
    14875 
    -
    14876  m_BlockInfos.clear();
    -
    14877 
    -
    14878  PostprocessMetadata();
    -
    14879 
    -
    14880  return VK_SUCCESS;
    -
    14881 }
    -
    14882 
    -
    14883 void VmaDefragmentationAlgorithm_Fast::PreprocessMetadata()
    -
    14884 {
    -
    14885  const size_t blockCount = m_pBlockVector->GetBlockCount();
    -
    14886  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    -
    14887  {
    -
    14888  VmaBlockMetadata_Generic* const pMetadata =
    -
    14889  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
    -
    14890  pMetadata->m_FreeCount = 0;
    -
    14891  pMetadata->m_SumFreeSize = pMetadata->GetSize();
    -
    14892  pMetadata->m_FreeSuballocationsBySize.clear();
    -
    14893  for(VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
    -
    14894  it != pMetadata->m_Suballocations.end(); )
    -
    14895  {
    -
    14896  if(it->type == VMA_SUBALLOCATION_TYPE_FREE)
    -
    14897  {
    -
    14898  VmaSuballocationList::iterator nextIt = it;
    -
    14899  ++nextIt;
    -
    14900  pMetadata->m_Suballocations.erase(it);
    -
    14901  it = nextIt;
    -
    14902  }
    -
    14903  else
    -
    14904  {
    -
    14905  ++it;
    -
    14906  }
    -
    14907  }
    -
    14908  }
    -
    14909 }
    -
    14910 
    -
    14911 void VmaDefragmentationAlgorithm_Fast::PostprocessMetadata()
    -
    14912 {
    -
    14913  const size_t blockCount = m_pBlockVector->GetBlockCount();
    -
    14914  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    -
    14915  {
    -
    14916  VmaBlockMetadata_Generic* const pMetadata =
    -
    14917  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
    -
    14918  const VkDeviceSize blockSize = pMetadata->GetSize();
    -
    14919 
    -
    14920  // No allocations in this block - entire area is free.
    -
    14921  if(pMetadata->m_Suballocations.empty())
    -
    14922  {
    -
    14923  pMetadata->m_FreeCount = 1;
    -
    14924  //pMetadata->m_SumFreeSize is already set to blockSize.
    -
    14925  VmaSuballocation suballoc = {
    -
    14926  0, // offset
    -
    14927  blockSize, // size
    -
    14928  VMA_NULL, // hAllocation
    -
    14929  VMA_SUBALLOCATION_TYPE_FREE };
    -
    14930  pMetadata->m_Suballocations.push_back(suballoc);
    -
    14931  pMetadata->RegisterFreeSuballocation(pMetadata->m_Suballocations.begin());
    -
    14932  }
    -
    14933  // There are some allocations in this block.
    -
    14934  else
    -
    14935  {
    -
    14936  VkDeviceSize offset = 0;
    -
    14937  VmaSuballocationList::iterator it;
    -
    14938  for(it = pMetadata->m_Suballocations.begin();
    -
    14939  it != pMetadata->m_Suballocations.end();
    -
    14940  ++it)
    -
    14941  {
    -
    14942  VMA_ASSERT(it->type != VMA_SUBALLOCATION_TYPE_FREE);
    -
    14943  VMA_ASSERT(it->offset >= offset);
    -
    14944 
    -
    14945  // Need to insert preceding free space.
    -
    14946  if(it->offset > offset)
    -
    14947  {
    -
    14948  ++pMetadata->m_FreeCount;
    -
    14949  const VkDeviceSize freeSize = it->offset - offset;
    -
    14950  VmaSuballocation suballoc = {
    -
    14951  offset, // offset
    -
    14952  freeSize, // size
    -
    14953  VMA_NULL, // hAllocation
    -
    14954  VMA_SUBALLOCATION_TYPE_FREE };
    -
    14955  VmaSuballocationList::iterator precedingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
    -
    14956  if(freeSize >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    14957  {
    -
    14958  pMetadata->m_FreeSuballocationsBySize.push_back(precedingFreeIt);
    -
    14959  }
    -
    14960  }
    -
    14961 
    -
    14962  pMetadata->m_SumFreeSize -= it->size;
    -
    14963  offset = it->offset + it->size;
    -
    14964  }
    -
    14965 
    -
    14966  // Need to insert trailing free space.
    -
    14967  if(offset < blockSize)
    -
    14968  {
    -
    14969  ++pMetadata->m_FreeCount;
    -
    14970  const VkDeviceSize freeSize = blockSize - offset;
    -
    14971  VmaSuballocation suballoc = {
    -
    14972  offset, // offset
    -
    14973  freeSize, // size
    -
    14974  VMA_NULL, // hAllocation
    -
    14975  VMA_SUBALLOCATION_TYPE_FREE };
    -
    14976  VMA_ASSERT(it == pMetadata->m_Suballocations.end());
    -
    14977  VmaSuballocationList::iterator trailingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
    -
    14978  if(freeSize > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    -
    14979  {
    -
    14980  pMetadata->m_FreeSuballocationsBySize.push_back(trailingFreeIt);
    -
    14981  }
    -
    14982  }
    -
    14983 
    -
    14984  VMA_SORT(
    -
    14985  pMetadata->m_FreeSuballocationsBySize.begin(),
    -
    14986  pMetadata->m_FreeSuballocationsBySize.end(),
    -
    14987  VmaSuballocationItemSizeLess());
    -
    14988  }
    -
    14989 
    -
    14990  VMA_HEAVY_ASSERT(pMetadata->Validate());
    -
    14991  }
    -
    14992 }
    -
    14993 
    -
    14994 void VmaDefragmentationAlgorithm_Fast::InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc)
    -
    14995 {
    -
    14996  // TODO: Optimize somehow. Remember iterator instead of searching for it linearly.
    -
    14997  VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
    -
    14998  while(it != pMetadata->m_Suballocations.end())
    -
    14999  {
    -
    15000  if(it->offset < suballoc.offset)
    -
    15001  {
    -
    15002  ++it;
    +
    14862  VMA_ASSERT(dstBlockInfoIndex < srcBlockInfoIndex);
    +
    14863  VMA_ASSERT(dstAllocOffset + srcAllocSize <= dstBlockSize);
    +
    14864 
    +
    14865  VmaSuballocation suballoc = *srcSuballocIt;
    +
    14866  suballoc.offset = dstAllocOffset;
    +
    14867  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlock, dstAllocOffset);
    +
    14868  dstOffset = dstAllocOffset + srcAllocSize;
    +
    14869  m_BytesMoved += srcAllocSize;
    +
    14870  ++m_AllocationsMoved;
    +
    14871 
    +
    14872  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
    +
    14873  ++nextSuballocIt;
    +
    14874  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
    +
    14875  srcSuballocIt = nextSuballocIt;
    +
    14876 
    +
    14877  pDstMetadata->m_Suballocations.push_back(suballoc);
    +
    14878 
    +
    14879  move.srcBlockIndex = srcOrigBlockIndex;
    +
    14880  move.dstBlockIndex = dstOrigBlockIndex;
    +
    14881  move.srcOffset = srcAllocOffset;
    +
    14882  move.dstOffset = dstAllocOffset;
    +
    14883  move.size = srcAllocSize;
    +
    14884 
    +
    14885  moves.push_back(move);
    +
    14886  }
    +
    14887  }
    +
    14888  }
    +
    14889  }
    +
    14890 
    +
    14891  m_BlockInfos.clear();
    +
    14892 
    +
    14893  PostprocessMetadata();
    +
    14894 
    +
    14895  return VK_SUCCESS;
    +
    14896 }
    +
    14897 
    +
    14898 void VmaDefragmentationAlgorithm_Fast::PreprocessMetadata()
    +
    14899 {
    +
    14900  const size_t blockCount = m_pBlockVector->GetBlockCount();
    +
    14901  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    +
    14902  {
    +
    14903  VmaBlockMetadata_Generic* const pMetadata =
    +
    14904  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
    +
    14905  pMetadata->m_FreeCount = 0;
    +
    14906  pMetadata->m_SumFreeSize = pMetadata->GetSize();
    +
    14907  pMetadata->m_FreeSuballocationsBySize.clear();
    +
    14908  for(VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
    +
    14909  it != pMetadata->m_Suballocations.end(); )
    +
    14910  {
    +
    14911  if(it->type == VMA_SUBALLOCATION_TYPE_FREE)
    +
    14912  {
    +
    14913  VmaSuballocationList::iterator nextIt = it;
    +
    14914  ++nextIt;
    +
    14915  pMetadata->m_Suballocations.erase(it);
    +
    14916  it = nextIt;
    +
    14917  }
    +
    14918  else
    +
    14919  {
    +
    14920  ++it;
    +
    14921  }
    +
    14922  }
    +
    14923  }
    +
    14924 }
    +
    14925 
    +
    14926 void VmaDefragmentationAlgorithm_Fast::PostprocessMetadata()
    +
    14927 {
    +
    14928  const size_t blockCount = m_pBlockVector->GetBlockCount();
    +
    14929  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    +
    14930  {
    +
    14931  VmaBlockMetadata_Generic* const pMetadata =
    +
    14932  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
    +
    14933  const VkDeviceSize blockSize = pMetadata->GetSize();
    +
    14934 
    +
    14935  // No allocations in this block - entire area is free.
    +
    14936  if(pMetadata->m_Suballocations.empty())
    +
    14937  {
    +
    14938  pMetadata->m_FreeCount = 1;
    +
    14939  //pMetadata->m_SumFreeSize is already set to blockSize.
    +
    14940  VmaSuballocation suballoc = {
    +
    14941  0, // offset
    +
    14942  blockSize, // size
    +
    14943  VMA_NULL, // hAllocation
    +
    14944  VMA_SUBALLOCATION_TYPE_FREE };
    +
    14945  pMetadata->m_Suballocations.push_back(suballoc);
    +
    14946  pMetadata->RegisterFreeSuballocation(pMetadata->m_Suballocations.begin());
    +
    14947  }
    +
    14948  // There are some allocations in this block.
    +
    14949  else
    +
    14950  {
    +
    14951  VkDeviceSize offset = 0;
    +
    14952  VmaSuballocationList::iterator it;
    +
    14953  for(it = pMetadata->m_Suballocations.begin();
    +
    14954  it != pMetadata->m_Suballocations.end();
    +
    14955  ++it)
    +
    14956  {
    +
    14957  VMA_ASSERT(it->type != VMA_SUBALLOCATION_TYPE_FREE);
    +
    14958  VMA_ASSERT(it->offset >= offset);
    +
    14959 
    +
    14960  // Need to insert preceding free space.
    +
    14961  if(it->offset > offset)
    +
    14962  {
    +
    14963  ++pMetadata->m_FreeCount;
    +
    14964  const VkDeviceSize freeSize = it->offset - offset;
    +
    14965  VmaSuballocation suballoc = {
    +
    14966  offset, // offset
    +
    14967  freeSize, // size
    +
    14968  VMA_NULL, // hAllocation
    +
    14969  VMA_SUBALLOCATION_TYPE_FREE };
    +
    14970  VmaSuballocationList::iterator precedingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
    +
    14971  if(freeSize >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    14972  {
    +
    14973  pMetadata->m_FreeSuballocationsBySize.push_back(precedingFreeIt);
    +
    14974  }
    +
    14975  }
    +
    14976 
    +
    14977  pMetadata->m_SumFreeSize -= it->size;
    +
    14978  offset = it->offset + it->size;
    +
    14979  }
    +
    14980 
    +
    14981  // Need to insert trailing free space.
    +
    14982  if(offset < blockSize)
    +
    14983  {
    +
    14984  ++pMetadata->m_FreeCount;
    +
    14985  const VkDeviceSize freeSize = blockSize - offset;
    +
    14986  VmaSuballocation suballoc = {
    +
    14987  offset, // offset
    +
    14988  freeSize, // size
    +
    14989  VMA_NULL, // hAllocation
    +
    14990  VMA_SUBALLOCATION_TYPE_FREE };
    +
    14991  VMA_ASSERT(it == pMetadata->m_Suballocations.end());
    +
    14992  VmaSuballocationList::iterator trailingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
    +
    14993  if(freeSize > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    +
    14994  {
    +
    14995  pMetadata->m_FreeSuballocationsBySize.push_back(trailingFreeIt);
    +
    14996  }
    +
    14997  }
    +
    14998 
    +
    14999  VMA_SORT(
    +
    15000  pMetadata->m_FreeSuballocationsBySize.begin(),
    +
    15001  pMetadata->m_FreeSuballocationsBySize.end(),
    +
    15002  VmaSuballocationItemSizeLess());
    15003  }
    -
    15004  }
    -
    15005  pMetadata->m_Suballocations.insert(it, suballoc);
    -
    15006 }
    -
    15007 
    -
    15009 // VmaBlockVectorDefragmentationContext
    -
    15010 
    -
    15011 VmaBlockVectorDefragmentationContext::VmaBlockVectorDefragmentationContext(
    -
    15012  VmaAllocator hAllocator,
    -
    15013  VmaPool hCustomPool,
    -
    15014  VmaBlockVector* pBlockVector,
    -
    15015  uint32_t currFrameIndex) :
    -
    15016  res(VK_SUCCESS),
    -
    15017  mutexLocked(false),
    -
    15018  blockContexts(VmaStlAllocator<VmaBlockDefragmentationContext>(hAllocator->GetAllocationCallbacks())),
    -
    15019  defragmentationMoves(VmaStlAllocator<VmaDefragmentationMove>(hAllocator->GetAllocationCallbacks())),
    -
    15020  defragmentationMovesProcessed(0),
    -
    15021  defragmentationMovesCommitted(0),
    -
    15022  hasDefragmentationPlan(0),
    -
    15023  m_hAllocator(hAllocator),
    -
    15024  m_hCustomPool(hCustomPool),
    -
    15025  m_pBlockVector(pBlockVector),
    -
    15026  m_CurrFrameIndex(currFrameIndex),
    -
    15027  m_pAlgorithm(VMA_NULL),
    -
    15028  m_Allocations(VmaStlAllocator<AllocInfo>(hAllocator->GetAllocationCallbacks())),
    -
    15029  m_AllAllocations(false)
    -
    15030 {
    -
    15031 }
    -
    15032 
    -
    15033 VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext()
    -
    15034 {
    -
    15035  vma_delete(m_hAllocator, m_pAlgorithm);
    -
    15036 }
    -
    15037 
    -
    15038 void VmaBlockVectorDefragmentationContext::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
    -
    15039 {
    -
    15040  AllocInfo info = { hAlloc, pChanged };
    -
    15041  m_Allocations.push_back(info);
    -
    15042 }
    -
    15043 
    -
    15044 void VmaBlockVectorDefragmentationContext::Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags)
    +
    15004 
    +
    15005  VMA_HEAVY_ASSERT(pMetadata->Validate());
    +
    15006  }
    +
    15007 }
    +
    15008 
    +
    15009 void VmaDefragmentationAlgorithm_Fast::InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc)
    +
    15010 {
    +
    15011  // TODO: Optimize somehow. Remember iterator instead of searching for it linearly.
    +
    15012  VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
    +
    15013  while(it != pMetadata->m_Suballocations.end())
    +
    15014  {
    +
    15015  if(it->offset < suballoc.offset)
    +
    15016  {
    +
    15017  ++it;
    +
    15018  }
    +
    15019  }
    +
    15020  pMetadata->m_Suballocations.insert(it, suballoc);
    +
    15021 }
    +
    15022 
    +
    15024 // VmaBlockVectorDefragmentationContext
    +
    15025 
    +
    15026 VmaBlockVectorDefragmentationContext::VmaBlockVectorDefragmentationContext(
    +
    15027  VmaAllocator hAllocator,
    +
    15028  VmaPool hCustomPool,
    +
    15029  VmaBlockVector* pBlockVector,
    +
    15030  uint32_t currFrameIndex) :
    +
    15031  res(VK_SUCCESS),
    +
    15032  mutexLocked(false),
    +
    15033  blockContexts(VmaStlAllocator<VmaBlockDefragmentationContext>(hAllocator->GetAllocationCallbacks())),
    +
    15034  defragmentationMoves(VmaStlAllocator<VmaDefragmentationMove>(hAllocator->GetAllocationCallbacks())),
    +
    15035  defragmentationMovesProcessed(0),
    +
    15036  defragmentationMovesCommitted(0),
    +
    15037  hasDefragmentationPlan(0),
    +
    15038  m_hAllocator(hAllocator),
    +
    15039  m_hCustomPool(hCustomPool),
    +
    15040  m_pBlockVector(pBlockVector),
    +
    15041  m_CurrFrameIndex(currFrameIndex),
    +
    15042  m_pAlgorithm(VMA_NULL),
    +
    15043  m_Allocations(VmaStlAllocator<AllocInfo>(hAllocator->GetAllocationCallbacks())),
    +
    15044  m_AllAllocations(false)
    15045 {
    -
    15046  const bool allAllocations = m_AllAllocations ||
    -
    15047  m_Allocations.size() == m_pBlockVector->CalcAllocationCount();
    -
    15048 
    -
    15049  /********************************
    -
    15050  HERE IS THE CHOICE OF DEFRAGMENTATION ALGORITHM.
    -
    15051  ********************************/
    +
    15046 }
    +
    15047 
    +
    15048 VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext()
    +
    15049 {
    +
    15050  vma_delete(m_hAllocator, m_pAlgorithm);
    +
    15051 }
    15052 
    -
    15053  /*
    -
    15054  Fast algorithm is supported only when certain criteria are met:
    -
    15055  - VMA_DEBUG_MARGIN is 0.
    -
    15056  - All allocations in this block vector are moveable.
    -
    15057  - There is no possibility of image/buffer granularity conflict.
    -
    15058  - The defragmentation is not incremental
    -
    15059  */
    -
    15060  if(VMA_DEBUG_MARGIN == 0 &&
    -
    15061  allAllocations &&
    -
    15062  !m_pBlockVector->IsBufferImageGranularityConflictPossible() &&
    -
    15063  !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL))
    -
    15064  {
    -
    15065  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Fast)(
    -
    15066  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
    -
    15067  }
    -
    15068  else
    -
    15069  {
    -
    15070  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Generic)(
    -
    15071  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
    -
    15072  }
    -
    15073 
    -
    15074  if(allAllocations)
    -
    15075  {
    -
    15076  m_pAlgorithm->AddAll();
    -
    15077  }
    -
    15078  else
    +
    15053 void VmaBlockVectorDefragmentationContext::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
    +
    15054 {
    +
    15055  AllocInfo info = { hAlloc, pChanged };
    +
    15056  m_Allocations.push_back(info);
    +
    15057 }
    +
    15058 
    +
    15059 void VmaBlockVectorDefragmentationContext::Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags)
    +
    15060 {
    +
    15061  const bool allAllocations = m_AllAllocations ||
    +
    15062  m_Allocations.size() == m_pBlockVector->CalcAllocationCount();
    +
    15063 
    +
    15064  /********************************
    +
    15065  HERE IS THE CHOICE OF DEFRAGMENTATION ALGORITHM.
    +
    15066  ********************************/
    +
    15067 
    +
    15068  /*
    +
    15069  Fast algorithm is supported only when certain criteria are met:
    +
    15070  - VMA_DEBUG_MARGIN is 0.
    +
    15071  - All allocations in this block vector are moveable.
    +
    15072  - There is no possibility of image/buffer granularity conflict.
    +
    15073  - The defragmentation is not incremental
    +
    15074  */
    +
    15075  if(VMA_DEBUG_MARGIN == 0 &&
    +
    15076  allAllocations &&
    +
    15077  !m_pBlockVector->IsBufferImageGranularityConflictPossible() &&
    +
    15078  !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL))
    15079  {
    -
    15080  for(size_t i = 0, count = m_Allocations.size(); i < count; ++i)
    -
    15081  {
    -
    15082  m_pAlgorithm->AddAllocation(m_Allocations[i].hAlloc, m_Allocations[i].pChanged);
    -
    15083  }
    -
    15084  }
    -
    15085 }
    -
    15086 
    -
    15088 // VmaDefragmentationContext
    -
    15089 
    -
    15090 VmaDefragmentationContext_T::VmaDefragmentationContext_T(
    -
    15091  VmaAllocator hAllocator,
    -
    15092  uint32_t currFrameIndex,
    -
    15093  uint32_t flags,
    -
    15094  VmaDefragmentationStats* pStats) :
    -
    15095  m_hAllocator(hAllocator),
    -
    15096  m_CurrFrameIndex(currFrameIndex),
    -
    15097  m_Flags(flags),
    -
    15098  m_pStats(pStats),
    -
    15099  m_CustomPoolContexts(VmaStlAllocator<VmaBlockVectorDefragmentationContext*>(hAllocator->GetAllocationCallbacks()))
    -
    15100 {
    -
    15101  memset(m_DefaultPoolContexts, 0, sizeof(m_DefaultPoolContexts));
    -
    15102 }
    -
    15103 
    -
    15104 VmaDefragmentationContext_T::~VmaDefragmentationContext_T()
    -
    15105 {
    -
    15106  for(size_t i = m_CustomPoolContexts.size(); i--; )
    -
    15107  {
    -
    15108  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[i];
    -
    15109  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
    -
    15110  vma_delete(m_hAllocator, pBlockVectorCtx);
    -
    15111  }
    -
    15112  for(size_t i = m_hAllocator->m_MemProps.memoryTypeCount; i--; )
    -
    15113  {
    -
    15114  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[i];
    -
    15115  if(pBlockVectorCtx)
    -
    15116  {
    -
    15117  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
    -
    15118  vma_delete(m_hAllocator, pBlockVectorCtx);
    -
    15119  }
    -
    15120  }
    -
    15121 }
    -
    15122 
    -
    15123 void VmaDefragmentationContext_T::AddPools(uint32_t poolCount, const VmaPool* pPools)
    -
    15124 {
    -
    15125  for(uint32_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
    -
    15126  {
    -
    15127  VmaPool pool = pPools[poolIndex];
    -
    15128  VMA_ASSERT(pool);
    -
    15129  // Pools with algorithm other than default are not defragmented.
    -
    15130  if(pool->m_BlockVector.GetAlgorithm() == 0)
    +
    15080  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Fast)(
    +
    15081  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
    +
    15082  }
    +
    15083  else
    +
    15084  {
    +
    15085  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Generic)(
    +
    15086  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
    +
    15087  }
    +
    15088 
    +
    15089  if(allAllocations)
    +
    15090  {
    +
    15091  m_pAlgorithm->AddAll();
    +
    15092  }
    +
    15093  else
    +
    15094  {
    +
    15095  for(size_t i = 0, count = m_Allocations.size(); i < count; ++i)
    +
    15096  {
    +
    15097  m_pAlgorithm->AddAllocation(m_Allocations[i].hAlloc, m_Allocations[i].pChanged);
    +
    15098  }
    +
    15099  }
    +
    15100 }
    +
    15101 
    +
    15103 // VmaDefragmentationContext
    +
    15104 
    +
    15105 VmaDefragmentationContext_T::VmaDefragmentationContext_T(
    +
    15106  VmaAllocator hAllocator,
    +
    15107  uint32_t currFrameIndex,
    +
    15108  uint32_t flags,
    +
    15109  VmaDefragmentationStats* pStats) :
    +
    15110  m_hAllocator(hAllocator),
    +
    15111  m_CurrFrameIndex(currFrameIndex),
    +
    15112  m_Flags(flags),
    +
    15113  m_pStats(pStats),
    +
    15114  m_CustomPoolContexts(VmaStlAllocator<VmaBlockVectorDefragmentationContext*>(hAllocator->GetAllocationCallbacks()))
    +
    15115 {
    +
    15116  memset(m_DefaultPoolContexts, 0, sizeof(m_DefaultPoolContexts));
    +
    15117 }
    +
    15118 
    +
    15119 VmaDefragmentationContext_T::~VmaDefragmentationContext_T()
    +
    15120 {
    +
    15121  for(size_t i = m_CustomPoolContexts.size(); i--; )
    +
    15122  {
    +
    15123  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[i];
    +
    15124  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
    +
    15125  vma_delete(m_hAllocator, pBlockVectorCtx);
    +
    15126  }
    +
    15127  for(size_t i = m_hAllocator->m_MemProps.memoryTypeCount; i--; )
    +
    15128  {
    +
    15129  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[i];
    +
    15130  if(pBlockVectorCtx)
    15131  {
    -
    15132  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
    -
    15133 
    -
    15134  for(size_t i = m_CustomPoolContexts.size(); i--; )
    -
    15135  {
    -
    15136  if(m_CustomPoolContexts[i]->GetCustomPool() == pool)
    -
    15137  {
    -
    15138  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
    -
    15139  break;
    -
    15140  }
    -
    15141  }
    -
    15142 
    -
    15143  if(!pBlockVectorDefragCtx)
    -
    15144  {
    -
    15145  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
    -
    15146  m_hAllocator,
    -
    15147  pool,
    -
    15148  &pool->m_BlockVector,
    -
    15149  m_CurrFrameIndex);
    -
    15150  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
    -
    15151  }
    -
    15152 
    -
    15153  pBlockVectorDefragCtx->AddAll();
    -
    15154  }
    -
    15155  }
    -
    15156 }
    +
    15132  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
    +
    15133  vma_delete(m_hAllocator, pBlockVectorCtx);
    +
    15134  }
    +
    15135  }
    +
    15136 }
    +
    15137 
    +
    15138 void VmaDefragmentationContext_T::AddPools(uint32_t poolCount, const VmaPool* pPools)
    +
    15139 {
    +
    15140  for(uint32_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
    +
    15141  {
    +
    15142  VmaPool pool = pPools[poolIndex];
    +
    15143  VMA_ASSERT(pool);
    +
    15144  // Pools with algorithm other than default are not defragmented.
    +
    15145  if(pool->m_BlockVector.GetAlgorithm() == 0)
    +
    15146  {
    +
    15147  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
    +
    15148 
    +
    15149  for(size_t i = m_CustomPoolContexts.size(); i--; )
    +
    15150  {
    +
    15151  if(m_CustomPoolContexts[i]->GetCustomPool() == pool)
    +
    15152  {
    +
    15153  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
    +
    15154  break;
    +
    15155  }
    +
    15156  }
    15157 
    -
    15158 void VmaDefragmentationContext_T::AddAllocations(
    -
    15159  uint32_t allocationCount,
    -
    15160  const VmaAllocation* pAllocations,
    -
    15161  VkBool32* pAllocationsChanged)
    -
    15162 {
    -
    15163  // Dispatch pAllocations among defragmentators. Create them when necessary.
    -
    15164  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    -
    15165  {
    -
    15166  const VmaAllocation hAlloc = pAllocations[allocIndex];
    -
    15167  VMA_ASSERT(hAlloc);
    -
    15168  // DedicatedAlloc cannot be defragmented.
    -
    15169  if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
    -
    15170  // Lost allocation cannot be defragmented.
    -
    15171  (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
    -
    15172  {
    -
    15173  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
    -
    15174 
    -
    15175  const VmaPool hAllocPool = hAlloc->GetBlock()->GetParentPool();
    -
    15176  // This allocation belongs to custom pool.
    -
    15177  if(hAllocPool != VK_NULL_HANDLE)
    -
    15178  {
    -
    15179  // Pools with algorithm other than default are not defragmented.
    -
    15180  if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)
    -
    15181  {
    -
    15182  for(size_t i = m_CustomPoolContexts.size(); i--; )
    -
    15183  {
    -
    15184  if(m_CustomPoolContexts[i]->GetCustomPool() == hAllocPool)
    -
    15185  {
    -
    15186  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
    -
    15187  break;
    -
    15188  }
    -
    15189  }
    -
    15190  if(!pBlockVectorDefragCtx)
    -
    15191  {
    -
    15192  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
    -
    15193  m_hAllocator,
    -
    15194  hAllocPool,
    -
    15195  &hAllocPool->m_BlockVector,
    -
    15196  m_CurrFrameIndex);
    -
    15197  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
    -
    15198  }
    -
    15199  }
    -
    15200  }
    -
    15201  // This allocation belongs to default pool.
    -
    15202  else
    -
    15203  {
    -
    15204  const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
    -
    15205  pBlockVectorDefragCtx = m_DefaultPoolContexts[memTypeIndex];
    -
    15206  if(!pBlockVectorDefragCtx)
    -
    15207  {
    -
    15208  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
    -
    15209  m_hAllocator,
    -
    15210  VMA_NULL, // hCustomPool
    -
    15211  m_hAllocator->m_pBlockVectors[memTypeIndex],
    -
    15212  m_CurrFrameIndex);
    -
    15213  m_DefaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx;
    +
    15158  if(!pBlockVectorDefragCtx)
    +
    15159  {
    +
    15160  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
    +
    15161  m_hAllocator,
    +
    15162  pool,
    +
    15163  &pool->m_BlockVector,
    +
    15164  m_CurrFrameIndex);
    +
    15165  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
    +
    15166  }
    +
    15167 
    +
    15168  pBlockVectorDefragCtx->AddAll();
    +
    15169  }
    +
    15170  }
    +
    15171 }
    +
    15172 
    +
    15173 void VmaDefragmentationContext_T::AddAllocations(
    +
    15174  uint32_t allocationCount,
    +
    15175  const VmaAllocation* pAllocations,
    +
    15176  VkBool32* pAllocationsChanged)
    +
    15177 {
    +
    15178  // Dispatch pAllocations among defragmentators. Create them when necessary.
    +
    15179  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    +
    15180  {
    +
    15181  const VmaAllocation hAlloc = pAllocations[allocIndex];
    +
    15182  VMA_ASSERT(hAlloc);
    +
    15183  // DedicatedAlloc cannot be defragmented.
    +
    15184  if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
    +
    15185  // Lost allocation cannot be defragmented.
    +
    15186  (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
    +
    15187  {
    +
    15188  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
    +
    15189 
    +
    15190  const VmaPool hAllocPool = hAlloc->GetBlock()->GetParentPool();
    +
    15191  // This allocation belongs to custom pool.
    +
    15192  if(hAllocPool != VK_NULL_HANDLE)
    +
    15193  {
    +
    15194  // Pools with algorithm other than default are not defragmented.
    +
    15195  if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)
    +
    15196  {
    +
    15197  for(size_t i = m_CustomPoolContexts.size(); i--; )
    +
    15198  {
    +
    15199  if(m_CustomPoolContexts[i]->GetCustomPool() == hAllocPool)
    +
    15200  {
    +
    15201  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
    +
    15202  break;
    +
    15203  }
    +
    15204  }
    +
    15205  if(!pBlockVectorDefragCtx)
    +
    15206  {
    +
    15207  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
    +
    15208  m_hAllocator,
    +
    15209  hAllocPool,
    +
    15210  &hAllocPool->m_BlockVector,
    +
    15211  m_CurrFrameIndex);
    +
    15212  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
    +
    15213  }
    15214  }
    15215  }
    -
    15216 
    -
    15217  if(pBlockVectorDefragCtx)
    +
    15216  // This allocation belongs to default pool.
    +
    15217  else
    15218  {
    -
    15219  VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ?
    -
    15220  &pAllocationsChanged[allocIndex] : VMA_NULL;
    -
    15221  pBlockVectorDefragCtx->AddAllocation(hAlloc, pChanged);
    -
    15222  }
    -
    15223  }
    -
    15224  }
    -
    15225 }
    -
    15226 
    -
    15227 VkResult VmaDefragmentationContext_T::Defragment(
    -
    15228  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
    -
    15229  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
    -
    15230  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags)
    -
    15231 {
    -
    15232  if(pStats)
    -
    15233  {
    -
    15234  memset(pStats, 0, sizeof(VmaDefragmentationStats));
    -
    15235  }
    -
    15236 
    -
    15237  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)
    -
    15238  {
    -
    15239  // For incremental defragmetnations, we just earmark how much we can move
    -
    15240  // The real meat is in the defragmentation steps
    -
    15241  m_MaxCpuBytesToMove = maxCpuBytesToMove;
    -
    15242  m_MaxCpuAllocationsToMove = maxCpuAllocationsToMove;
    -
    15243 
    -
    15244  m_MaxGpuBytesToMove = maxGpuBytesToMove;
    -
    15245  m_MaxGpuAllocationsToMove = maxGpuAllocationsToMove;
    -
    15246 
    -
    15247  if(m_MaxCpuBytesToMove == 0 && m_MaxCpuAllocationsToMove == 0 &&
    -
    15248  m_MaxGpuBytesToMove == 0 && m_MaxGpuAllocationsToMove == 0)
    -
    15249  return VK_SUCCESS;
    -
    15250 
    -
    15251  return VK_NOT_READY;
    -
    15252  }
    -
    15253 
    -
    15254  if(commandBuffer == VK_NULL_HANDLE)
    -
    15255  {
    -
    15256  maxGpuBytesToMove = 0;
    -
    15257  maxGpuAllocationsToMove = 0;
    -
    15258  }
    -
    15259 
    -
    15260  VkResult res = VK_SUCCESS;
    +
    15219  const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
    +
    15220  pBlockVectorDefragCtx = m_DefaultPoolContexts[memTypeIndex];
    +
    15221  if(!pBlockVectorDefragCtx)
    +
    15222  {
    +
    15223  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
    +
    15224  m_hAllocator,
    +
    15225  VMA_NULL, // hCustomPool
    +
    15226  m_hAllocator->m_pBlockVectors[memTypeIndex],
    +
    15227  m_CurrFrameIndex);
    +
    15228  m_DefaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx;
    +
    15229  }
    +
    15230  }
    +
    15231 
    +
    15232  if(pBlockVectorDefragCtx)
    +
    15233  {
    +
    15234  VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ?
    +
    15235  &pAllocationsChanged[allocIndex] : VMA_NULL;
    +
    15236  pBlockVectorDefragCtx->AddAllocation(hAlloc, pChanged);
    +
    15237  }
    +
    15238  }
    +
    15239  }
    +
    15240 }
    +
    15241 
    +
    15242 VkResult VmaDefragmentationContext_T::Defragment(
    +
    15243  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
    +
    15244  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
    +
    15245  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags)
    +
    15246 {
    +
    15247  if(pStats)
    +
    15248  {
    +
    15249  memset(pStats, 0, sizeof(VmaDefragmentationStats));
    +
    15250  }
    +
    15251 
    +
    15252  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL)
    +
    15253  {
    +
    15254  // For incremental defragmetnations, we just earmark how much we can move
    +
    15255  // The real meat is in the defragmentation steps
    +
    15256  m_MaxCpuBytesToMove = maxCpuBytesToMove;
    +
    15257  m_MaxCpuAllocationsToMove = maxCpuAllocationsToMove;
    +
    15258 
    +
    15259  m_MaxGpuBytesToMove = maxGpuBytesToMove;
    +
    15260  m_MaxGpuAllocationsToMove = maxGpuAllocationsToMove;
    15261 
    -
    15262  // Process default pools.
    -
    15263  for(uint32_t memTypeIndex = 0;
    -
    15264  memTypeIndex < m_hAllocator->GetMemoryTypeCount() && res >= VK_SUCCESS;
    -
    15265  ++memTypeIndex)
    -
    15266  {
    -
    15267  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
    -
    15268  if(pBlockVectorCtx)
    -
    15269  {
    -
    15270  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
    -
    15271  pBlockVectorCtx->GetBlockVector()->Defragment(
    -
    15272  pBlockVectorCtx,
    -
    15273  pStats, flags,
    -
    15274  maxCpuBytesToMove, maxCpuAllocationsToMove,
    -
    15275  maxGpuBytesToMove, maxGpuAllocationsToMove,
    -
    15276  commandBuffer);
    -
    15277  if(pBlockVectorCtx->res != VK_SUCCESS)
    -
    15278  {
    -
    15279  res = pBlockVectorCtx->res;
    -
    15280  }
    -
    15281  }
    -
    15282  }
    -
    15283 
    -
    15284  // Process custom pools.
    -
    15285  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
    -
    15286  customCtxIndex < customCtxCount && res >= VK_SUCCESS;
    -
    15287  ++customCtxIndex)
    -
    15288  {
    -
    15289  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
    -
    15290  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
    -
    15291  pBlockVectorCtx->GetBlockVector()->Defragment(
    -
    15292  pBlockVectorCtx,
    -
    15293  pStats, flags,
    -
    15294  maxCpuBytesToMove, maxCpuAllocationsToMove,
    -
    15295  maxGpuBytesToMove, maxGpuAllocationsToMove,
    -
    15296  commandBuffer);
    -
    15297  if(pBlockVectorCtx->res != VK_SUCCESS)
    -
    15298  {
    -
    15299  res = pBlockVectorCtx->res;
    -
    15300  }
    -
    15301  }
    -
    15302 
    -
    15303  return res;
    -
    15304 }
    -
    15305 
    -
    15306 VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo)
    -
    15307 {
    -
    15308  VmaDefragmentationPassMoveInfo* pCurrentMove = pInfo->pMoves;
    -
    15309  uint32_t movesLeft = pInfo->moveCount;
    -
    15310 
    -
    15311  // Process default pools.
    -
    15312  for(uint32_t memTypeIndex = 0;
    -
    15313  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
    -
    15314  ++memTypeIndex)
    -
    15315  {
    -
    15316  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
    -
    15317  if(pBlockVectorCtx)
    -
    15318  {
    -
    15319  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
    +
    15262  if(m_MaxCpuBytesToMove == 0 && m_MaxCpuAllocationsToMove == 0 &&
    +
    15263  m_MaxGpuBytesToMove == 0 && m_MaxGpuAllocationsToMove == 0)
    +
    15264  return VK_SUCCESS;
    +
    15265 
    +
    15266  return VK_NOT_READY;
    +
    15267  }
    +
    15268 
    +
    15269  if(commandBuffer == VK_NULL_HANDLE)
    +
    15270  {
    +
    15271  maxGpuBytesToMove = 0;
    +
    15272  maxGpuAllocationsToMove = 0;
    +
    15273  }
    +
    15274 
    +
    15275  VkResult res = VK_SUCCESS;
    +
    15276 
    +
    15277  // Process default pools.
    +
    15278  for(uint32_t memTypeIndex = 0;
    +
    15279  memTypeIndex < m_hAllocator->GetMemoryTypeCount() && res >= VK_SUCCESS;
    +
    15280  ++memTypeIndex)
    +
    15281  {
    +
    15282  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
    +
    15283  if(pBlockVectorCtx)
    +
    15284  {
    +
    15285  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
    +
    15286  pBlockVectorCtx->GetBlockVector()->Defragment(
    +
    15287  pBlockVectorCtx,
    +
    15288  pStats, flags,
    +
    15289  maxCpuBytesToMove, maxCpuAllocationsToMove,
    +
    15290  maxGpuBytesToMove, maxGpuAllocationsToMove,
    +
    15291  commandBuffer);
    +
    15292  if(pBlockVectorCtx->res != VK_SUCCESS)
    +
    15293  {
    +
    15294  res = pBlockVectorCtx->res;
    +
    15295  }
    +
    15296  }
    +
    15297  }
    +
    15298 
    +
    15299  // Process custom pools.
    +
    15300  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
    +
    15301  customCtxIndex < customCtxCount && res >= VK_SUCCESS;
    +
    15302  ++customCtxIndex)
    +
    15303  {
    +
    15304  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
    +
    15305  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
    +
    15306  pBlockVectorCtx->GetBlockVector()->Defragment(
    +
    15307  pBlockVectorCtx,
    +
    15308  pStats, flags,
    +
    15309  maxCpuBytesToMove, maxCpuAllocationsToMove,
    +
    15310  maxGpuBytesToMove, maxGpuAllocationsToMove,
    +
    15311  commandBuffer);
    +
    15312  if(pBlockVectorCtx->res != VK_SUCCESS)
    +
    15313  {
    +
    15314  res = pBlockVectorCtx->res;
    +
    15315  }
    +
    15316  }
    +
    15317 
    +
    15318  return res;
    +
    15319 }
    15320 
    -
    15321  if(!pBlockVectorCtx->hasDefragmentationPlan)
    -
    15322  {
    -
    15323  pBlockVectorCtx->GetBlockVector()->Defragment(
    -
    15324  pBlockVectorCtx,
    -
    15325  m_pStats, m_Flags,
    -
    15326  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
    -
    15327  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
    -
    15328  VK_NULL_HANDLE);
    -
    15329 
    -
    15330  if(pBlockVectorCtx->res < VK_SUCCESS)
    -
    15331  continue;
    -
    15332 
    -
    15333  pBlockVectorCtx->hasDefragmentationPlan = true;
    -
    15334  }
    +
    15321 VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo)
    +
    15322 {
    +
    15323  VmaDefragmentationPassMoveInfo* pCurrentMove = pInfo->pMoves;
    +
    15324  uint32_t movesLeft = pInfo->moveCount;
    +
    15325 
    +
    15326  // Process default pools.
    +
    15327  for(uint32_t memTypeIndex = 0;
    +
    15328  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
    +
    15329  ++memTypeIndex)
    +
    15330  {
    +
    15331  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
    +
    15332  if(pBlockVectorCtx)
    +
    15333  {
    +
    15334  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
    15335 
    -
    15336  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
    -
    15337  pBlockVectorCtx,
    -
    15338  pCurrentMove, movesLeft);
    -
    15339 
    -
    15340  movesLeft -= processed;
    -
    15341  pCurrentMove += processed;
    -
    15342  }
    -
    15343  }
    +
    15336  if(!pBlockVectorCtx->hasDefragmentationPlan)
    +
    15337  {
    +
    15338  pBlockVectorCtx->GetBlockVector()->Defragment(
    +
    15339  pBlockVectorCtx,
    +
    15340  m_pStats, m_Flags,
    +
    15341  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
    +
    15342  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
    +
    15343  VK_NULL_HANDLE);
    15344 
    -
    15345  // Process custom pools.
    -
    15346  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
    -
    15347  customCtxIndex < customCtxCount;
    -
    15348  ++customCtxIndex)
    -
    15349  {
    -
    15350  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
    -
    15351  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
    -
    15352 
    -
    15353  if(!pBlockVectorCtx->hasDefragmentationPlan)
    -
    15354  {
    -
    15355  pBlockVectorCtx->GetBlockVector()->Defragment(
    -
    15356  pBlockVectorCtx,
    -
    15357  m_pStats, m_Flags,
    -
    15358  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
    -
    15359  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
    -
    15360  VK_NULL_HANDLE);
    -
    15361 
    -
    15362  if(pBlockVectorCtx->res < VK_SUCCESS)
    -
    15363  continue;
    -
    15364 
    -
    15365  pBlockVectorCtx->hasDefragmentationPlan = true;
    -
    15366  }
    +
    15345  if(pBlockVectorCtx->res < VK_SUCCESS)
    +
    15346  continue;
    +
    15347 
    +
    15348  pBlockVectorCtx->hasDefragmentationPlan = true;
    +
    15349  }
    +
    15350 
    +
    15351  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
    +
    15352  pBlockVectorCtx,
    +
    15353  pCurrentMove, movesLeft);
    +
    15354 
    +
    15355  movesLeft -= processed;
    +
    15356  pCurrentMove += processed;
    +
    15357  }
    +
    15358  }
    +
    15359 
    +
    15360  // Process custom pools.
    +
    15361  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
    +
    15362  customCtxIndex < customCtxCount;
    +
    15363  ++customCtxIndex)
    +
    15364  {
    +
    15365  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
    +
    15366  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
    15367 
    -
    15368  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
    -
    15369  pBlockVectorCtx,
    -
    15370  pCurrentMove, movesLeft);
    -
    15371 
    -
    15372  movesLeft -= processed;
    -
    15373  pCurrentMove += processed;
    -
    15374  }
    -
    15375 
    -
    15376  pInfo->moveCount = pInfo->moveCount - movesLeft;
    -
    15377 
    -
    15378  return VK_SUCCESS;
    -
    15379 }
    -
    15380 VkResult VmaDefragmentationContext_T::DefragmentPassEnd()
    -
    15381 {
    -
    15382  VkResult res = VK_SUCCESS;
    -
    15383 
    -
    15384  // Process default pools.
    -
    15385  for(uint32_t memTypeIndex = 0;
    -
    15386  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
    -
    15387  ++memTypeIndex)
    -
    15388  {
    -
    15389  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
    -
    15390  if(pBlockVectorCtx)
    -
    15391  {
    -
    15392  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
    -
    15393 
    -
    15394  if(!pBlockVectorCtx->hasDefragmentationPlan)
    -
    15395  {
    -
    15396  res = VK_NOT_READY;
    -
    15397  continue;
    -
    15398  }
    -
    15399 
    -
    15400  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
    -
    15401  pBlockVectorCtx, m_pStats);
    -
    15402 
    -
    15403  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
    -
    15404  res = VK_NOT_READY;
    -
    15405  }
    -
    15406  }
    -
    15407 
    -
    15408  // Process custom pools.
    -
    15409  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
    -
    15410  customCtxIndex < customCtxCount;
    -
    15411  ++customCtxIndex)
    -
    15412  {
    -
    15413  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
    -
    15414  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
    -
    15415 
    -
    15416  if(!pBlockVectorCtx->hasDefragmentationPlan)
    -
    15417  {
    -
    15418  res = VK_NOT_READY;
    -
    15419  continue;
    +
    15368  if(!pBlockVectorCtx->hasDefragmentationPlan)
    +
    15369  {
    +
    15370  pBlockVectorCtx->GetBlockVector()->Defragment(
    +
    15371  pBlockVectorCtx,
    +
    15372  m_pStats, m_Flags,
    +
    15373  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
    +
    15374  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
    +
    15375  VK_NULL_HANDLE);
    +
    15376 
    +
    15377  if(pBlockVectorCtx->res < VK_SUCCESS)
    +
    15378  continue;
    +
    15379 
    +
    15380  pBlockVectorCtx->hasDefragmentationPlan = true;
    +
    15381  }
    +
    15382 
    +
    15383  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
    +
    15384  pBlockVectorCtx,
    +
    15385  pCurrentMove, movesLeft);
    +
    15386 
    +
    15387  movesLeft -= processed;
    +
    15388  pCurrentMove += processed;
    +
    15389  }
    +
    15390 
    +
    15391  pInfo->moveCount = pInfo->moveCount - movesLeft;
    +
    15392 
    +
    15393  return VK_SUCCESS;
    +
    15394 }
    +
    15395 VkResult VmaDefragmentationContext_T::DefragmentPassEnd()
    +
    15396 {
    +
    15397  VkResult res = VK_SUCCESS;
    +
    15398 
    +
    15399  // Process default pools.
    +
    15400  for(uint32_t memTypeIndex = 0;
    +
    15401  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
    +
    15402  ++memTypeIndex)
    +
    15403  {
    +
    15404  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
    +
    15405  if(pBlockVectorCtx)
    +
    15406  {
    +
    15407  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
    +
    15408 
    +
    15409  if(!pBlockVectorCtx->hasDefragmentationPlan)
    +
    15410  {
    +
    15411  res = VK_NOT_READY;
    +
    15412  continue;
    +
    15413  }
    +
    15414 
    +
    15415  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
    +
    15416  pBlockVectorCtx, m_pStats);
    +
    15417 
    +
    15418  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
    +
    15419  res = VK_NOT_READY;
    15420  }
    -
    15421 
    -
    15422  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
    -
    15423  pBlockVectorCtx, m_pStats);
    -
    15424 
    -
    15425  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
    -
    15426  res = VK_NOT_READY;
    -
    15427  }
    -
    15428 
    -
    15429  return res;
    -
    15430 }
    -
    15431 
    -
    15433 // VmaRecorder
    -
    15434 
    -
    15435 #if VMA_RECORDING_ENABLED
    +
    15421  }
    +
    15422 
    +
    15423  // Process custom pools.
    +
    15424  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
    +
    15425  customCtxIndex < customCtxCount;
    +
    15426  ++customCtxIndex)
    +
    15427  {
    +
    15428  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
    +
    15429  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
    +
    15430 
    +
    15431  if(!pBlockVectorCtx->hasDefragmentationPlan)
    +
    15432  {
    +
    15433  res = VK_NOT_READY;
    +
    15434  continue;
    +
    15435  }
    15436 
    -
    15437 VmaRecorder::VmaRecorder() :
    -
    15438  m_UseMutex(true),
    -
    15439  m_Flags(0),
    -
    15440  m_File(VMA_NULL),
    -
    15441  m_RecordingStartTime(std::chrono::high_resolution_clock::now())
    -
    15442 {
    -
    15443 }
    -
    15444 
    -
    15445 VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
    -
    15446 {
    -
    15447  m_UseMutex = useMutex;
    -
    15448  m_Flags = settings.flags;
    +
    15437  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
    +
    15438  pBlockVectorCtx, m_pStats);
    +
    15439 
    +
    15440  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
    +
    15441  res = VK_NOT_READY;
    +
    15442  }
    +
    15443 
    +
    15444  return res;
    +
    15445 }
    +
    15446 
    +
    15448 // VmaRecorder
    15449 
    -
    15450 #if defined(_WIN32)
    -
    15451  // Open file for writing.
    -
    15452  errno_t err = fopen_s(&m_File, settings.pFilePath, "wb");
    -
    15453 
    -
    15454  if(err != 0)
    -
    15455  {
    -
    15456  return VK_ERROR_INITIALIZATION_FAILED;
    -
    15457  }
    -
    15458 #else
    -
    15459  // Open file for writing.
    -
    15460  m_File = fopen(settings.pFilePath, "wb");
    -
    15461 
    -
    15462  if(m_File == 0)
    -
    15463  {
    -
    15464  return VK_ERROR_INITIALIZATION_FAILED;
    -
    15465  }
    -
    15466 #endif
    -
    15467 
    -
    15468  // Write header.
    -
    15469  fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
    -
    15470  fprintf(m_File, "%s\n", "1,8");
    -
    15471 
    -
    15472  return VK_SUCCESS;
    -
    15473 }
    -
    15474 
    -
    15475 VmaRecorder::~VmaRecorder()
    -
    15476 {
    -
    15477  if(m_File != VMA_NULL)
    +
    15450 #if VMA_RECORDING_ENABLED
    +
    15451 
    +
    15452 VmaRecorder::VmaRecorder() :
    +
    15453  m_UseMutex(true),
    +
    15454  m_Flags(0),
    +
    15455  m_File(VMA_NULL),
    +
    15456  m_RecordingStartTime(std::chrono::high_resolution_clock::now())
    +
    15457 {
    +
    15458 }
    +
    15459 
    +
    15460 VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
    +
    15461 {
    +
    15462  m_UseMutex = useMutex;
    +
    15463  m_Flags = settings.flags;
    +
    15464 
    +
    15465 #if defined(_WIN32)
    +
    15466  // Open file for writing.
    +
    15467  errno_t err = fopen_s(&m_File, settings.pFilePath, "wb");
    +
    15468 
    +
    15469  if(err != 0)
    +
    15470  {
    +
    15471  return VK_ERROR_INITIALIZATION_FAILED;
    +
    15472  }
    +
    15473 #else
    +
    15474  // Open file for writing.
    +
    15475  m_File = fopen(settings.pFilePath, "wb");
    +
    15476 
    +
    15477  if(m_File == 0)
    15478  {
    -
    15479  fclose(m_File);
    +
    15479  return VK_ERROR_INITIALIZATION_FAILED;
    15480  }
    -
    15481 }
    +
    15481 #endif
    15482 
    -
    15483 void VmaRecorder::RecordCreateAllocator(uint32_t frameIndex)
    -
    15484 {
    -
    15485  CallParams callParams;
    -
    15486  GetBasicParams(callParams);
    -
    15487 
    -
    15488  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15489  fprintf(m_File, "%u,%.3f,%u,vmaCreateAllocator\n", callParams.threadId, callParams.time, frameIndex);
    -
    15490  Flush();
    -
    15491 }
    -
    15492 
    -
    15493 void VmaRecorder::RecordDestroyAllocator(uint32_t frameIndex)
    -
    15494 {
    -
    15495  CallParams callParams;
    -
    15496  GetBasicParams(callParams);
    +
    15483  // Write header.
    +
    15484  fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
    +
    15485  fprintf(m_File, "%s\n", "1,8");
    +
    15486 
    +
    15487  return VK_SUCCESS;
    +
    15488 }
    +
    15489 
    +
    15490 VmaRecorder::~VmaRecorder()
    +
    15491 {
    +
    15492  if(m_File != VMA_NULL)
    +
    15493  {
    +
    15494  fclose(m_File);
    +
    15495  }
    +
    15496 }
    15497 
    -
    15498  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15499  fprintf(m_File, "%u,%.3f,%u,vmaDestroyAllocator\n", callParams.threadId, callParams.time, frameIndex);
    -
    15500  Flush();
    -
    15501 }
    +
    15498 void VmaRecorder::RecordCreateAllocator(uint32_t frameIndex)
    +
    15499 {
    +
    15500  CallParams callParams;
    +
    15501  GetBasicParams(callParams);
    15502 
    -
    15503 void VmaRecorder::RecordCreatePool(uint32_t frameIndex, const VmaPoolCreateInfo& createInfo, VmaPool pool)
    -
    15504 {
    -
    15505  CallParams callParams;
    -
    15506  GetBasicParams(callParams);
    +
    15503  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15504  fprintf(m_File, "%u,%.3f,%u,vmaCreateAllocator\n", callParams.threadId, callParams.time, frameIndex);
    +
    15505  Flush();
    +
    15506 }
    15507 
    -
    15508  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15509  fprintf(m_File, "%u,%.3f,%u,vmaCreatePool,%u,%u,%llu,%llu,%llu,%u,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15510  createInfo.memoryTypeIndex,
    -
    15511  createInfo.flags,
    -
    15512  createInfo.blockSize,
    -
    15513  (uint64_t)createInfo.minBlockCount,
    -
    15514  (uint64_t)createInfo.maxBlockCount,
    -
    15515  createInfo.frameInUseCount,
    -
    15516  pool);
    -
    15517  Flush();
    -
    15518 }
    -
    15519 
    -
    15520 void VmaRecorder::RecordDestroyPool(uint32_t frameIndex, VmaPool pool)
    -
    15521 {
    -
    15522  CallParams callParams;
    -
    15523  GetBasicParams(callParams);
    -
    15524 
    -
    15525  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15526  fprintf(m_File, "%u,%.3f,%u,vmaDestroyPool,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15527  pool);
    -
    15528  Flush();
    -
    15529 }
    -
    15530 
    -
    15531 void VmaRecorder::RecordAllocateMemory(uint32_t frameIndex,
    -
    15532  const VkMemoryRequirements& vkMemReq,
    -
    15533  const VmaAllocationCreateInfo& createInfo,
    -
    15534  VmaAllocation allocation)
    -
    15535 {
    -
    15536  CallParams callParams;
    -
    15537  GetBasicParams(callParams);
    -
    15538 
    -
    15539  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15540  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    -
    15541  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemory,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15542  vkMemReq.size,
    -
    15543  vkMemReq.alignment,
    -
    15544  vkMemReq.memoryTypeBits,
    -
    15545  createInfo.flags,
    -
    15546  createInfo.usage,
    -
    15547  createInfo.requiredFlags,
    -
    15548  createInfo.preferredFlags,
    -
    15549  createInfo.memoryTypeBits,
    -
    15550  createInfo.pool,
    -
    15551  allocation,
    -
    15552  userDataStr.GetString());
    -
    15553  Flush();
    -
    15554 }
    -
    15555 
    -
    15556 void VmaRecorder::RecordAllocateMemoryPages(uint32_t frameIndex,
    -
    15557  const VkMemoryRequirements& vkMemReq,
    -
    15558  const VmaAllocationCreateInfo& createInfo,
    -
    15559  uint64_t allocationCount,
    -
    15560  const VmaAllocation* pAllocations)
    -
    15561 {
    -
    15562  CallParams callParams;
    -
    15563  GetBasicParams(callParams);
    -
    15564 
    -
    15565  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15566  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    -
    15567  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryPages,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,", callParams.threadId, callParams.time, frameIndex,
    -
    15568  vkMemReq.size,
    -
    15569  vkMemReq.alignment,
    -
    15570  vkMemReq.memoryTypeBits,
    -
    15571  createInfo.flags,
    -
    15572  createInfo.usage,
    -
    15573  createInfo.requiredFlags,
    -
    15574  createInfo.preferredFlags,
    -
    15575  createInfo.memoryTypeBits,
    -
    15576  createInfo.pool);
    -
    15577  PrintPointerList(allocationCount, pAllocations);
    -
    15578  fprintf(m_File, ",%s\n", userDataStr.GetString());
    -
    15579  Flush();
    -
    15580 }
    -
    15581 
    -
    15582 void VmaRecorder::RecordAllocateMemoryForBuffer(uint32_t frameIndex,
    -
    15583  const VkMemoryRequirements& vkMemReq,
    -
    15584  bool requiresDedicatedAllocation,
    -
    15585  bool prefersDedicatedAllocation,
    -
    15586  const VmaAllocationCreateInfo& createInfo,
    -
    15587  VmaAllocation allocation)
    -
    15588 {
    -
    15589  CallParams callParams;
    -
    15590  GetBasicParams(callParams);
    -
    15591 
    -
    15592  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15593  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    -
    15594  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForBuffer,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15595  vkMemReq.size,
    -
    15596  vkMemReq.alignment,
    -
    15597  vkMemReq.memoryTypeBits,
    -
    15598  requiresDedicatedAllocation ? 1 : 0,
    -
    15599  prefersDedicatedAllocation ? 1 : 0,
    -
    15600  createInfo.flags,
    -
    15601  createInfo.usage,
    -
    15602  createInfo.requiredFlags,
    -
    15603  createInfo.preferredFlags,
    -
    15604  createInfo.memoryTypeBits,
    -
    15605  createInfo.pool,
    -
    15606  allocation,
    -
    15607  userDataStr.GetString());
    -
    15608  Flush();
    -
    15609 }
    -
    15610 
    -
    15611 void VmaRecorder::RecordAllocateMemoryForImage(uint32_t frameIndex,
    -
    15612  const VkMemoryRequirements& vkMemReq,
    -
    15613  bool requiresDedicatedAllocation,
    -
    15614  bool prefersDedicatedAllocation,
    -
    15615  const VmaAllocationCreateInfo& createInfo,
    -
    15616  VmaAllocation allocation)
    -
    15617 {
    -
    15618  CallParams callParams;
    -
    15619  GetBasicParams(callParams);
    -
    15620 
    -
    15621  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15622  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    -
    15623  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForImage,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15624  vkMemReq.size,
    -
    15625  vkMemReq.alignment,
    -
    15626  vkMemReq.memoryTypeBits,
    -
    15627  requiresDedicatedAllocation ? 1 : 0,
    -
    15628  prefersDedicatedAllocation ? 1 : 0,
    -
    15629  createInfo.flags,
    -
    15630  createInfo.usage,
    -
    15631  createInfo.requiredFlags,
    -
    15632  createInfo.preferredFlags,
    -
    15633  createInfo.memoryTypeBits,
    -
    15634  createInfo.pool,
    -
    15635  allocation,
    -
    15636  userDataStr.GetString());
    -
    15637  Flush();
    -
    15638 }
    -
    15639 
    -
    15640 void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
    -
    15641  VmaAllocation allocation)
    -
    15642 {
    -
    15643  CallParams callParams;
    -
    15644  GetBasicParams(callParams);
    -
    15645 
    -
    15646  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15647  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15648  allocation);
    -
    15649  Flush();
    -
    15650 }
    -
    15651 
    -
    15652 void VmaRecorder::RecordFreeMemoryPages(uint32_t frameIndex,
    -
    15653  uint64_t allocationCount,
    -
    15654  const VmaAllocation* pAllocations)
    -
    15655 {
    -
    15656  CallParams callParams;
    -
    15657  GetBasicParams(callParams);
    -
    15658 
    -
    15659  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15660  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemoryPages,", callParams.threadId, callParams.time, frameIndex);
    -
    15661  PrintPointerList(allocationCount, pAllocations);
    -
    15662  fprintf(m_File, "\n");
    -
    15663  Flush();
    -
    15664 }
    -
    15665 
    -
    15666 void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
    -
    15667  VmaAllocation allocation,
    -
    15668  const void* pUserData)
    -
    15669 {
    -
    15670  CallParams callParams;
    -
    15671  GetBasicParams(callParams);
    -
    15672 
    -
    15673  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15674  UserDataString userDataStr(
    -
    15675  allocation->IsUserDataString() ? VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT : 0,
    -
    15676  pUserData);
    -
    15677  fprintf(m_File, "%u,%.3f,%u,vmaSetAllocationUserData,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15678  allocation,
    -
    15679  userDataStr.GetString());
    -
    15680  Flush();
    -
    15681 }
    -
    15682 
    -
    15683 void VmaRecorder::RecordCreateLostAllocation(uint32_t frameIndex,
    -
    15684  VmaAllocation allocation)
    -
    15685 {
    -
    15686  CallParams callParams;
    -
    15687  GetBasicParams(callParams);
    -
    15688 
    -
    15689  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15690  fprintf(m_File, "%u,%.3f,%u,vmaCreateLostAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15691  allocation);
    -
    15692  Flush();
    -
    15693 }
    -
    15694 
    -
    15695 void VmaRecorder::RecordMapMemory(uint32_t frameIndex,
    -
    15696  VmaAllocation allocation)
    -
    15697 {
    -
    15698  CallParams callParams;
    -
    15699  GetBasicParams(callParams);
    -
    15700 
    -
    15701  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15702  fprintf(m_File, "%u,%.3f,%u,vmaMapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15703  allocation);
    -
    15704  Flush();
    -
    15705 }
    -
    15706 
    -
    15707 void VmaRecorder::RecordUnmapMemory(uint32_t frameIndex,
    -
    15708  VmaAllocation allocation)
    -
    15709 {
    -
    15710  CallParams callParams;
    -
    15711  GetBasicParams(callParams);
    -
    15712 
    -
    15713  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15714  fprintf(m_File, "%u,%.3f,%u,vmaUnmapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15715  allocation);
    -
    15716  Flush();
    -
    15717 }
    -
    15718 
    -
    15719 void VmaRecorder::RecordFlushAllocation(uint32_t frameIndex,
    -
    15720  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    -
    15721 {
    -
    15722  CallParams callParams;
    -
    15723  GetBasicParams(callParams);
    -
    15724 
    -
    15725  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15726  fprintf(m_File, "%u,%.3f,%u,vmaFlushAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
    -
    15727  allocation,
    -
    15728  offset,
    -
    15729  size);
    -
    15730  Flush();
    -
    15731 }
    -
    15732 
    -
    15733 void VmaRecorder::RecordInvalidateAllocation(uint32_t frameIndex,
    -
    15734  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    -
    15735 {
    -
    15736  CallParams callParams;
    -
    15737  GetBasicParams(callParams);
    -
    15738 
    -
    15739  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15740  fprintf(m_File, "%u,%.3f,%u,vmaInvalidateAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
    -
    15741  allocation,
    -
    15742  offset,
    -
    15743  size);
    -
    15744  Flush();
    -
    15745 }
    -
    15746 
    -
    15747 void VmaRecorder::RecordCreateBuffer(uint32_t frameIndex,
    -
    15748  const VkBufferCreateInfo& bufCreateInfo,
    -
    15749  const VmaAllocationCreateInfo& allocCreateInfo,
    -
    15750  VmaAllocation allocation)
    -
    15751 {
    -
    15752  CallParams callParams;
    -
    15753  GetBasicParams(callParams);
    -
    15754 
    -
    15755  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15756  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
    -
    15757  fprintf(m_File, "%u,%.3f,%u,vmaCreateBuffer,%u,%llu,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15758  bufCreateInfo.flags,
    -
    15759  bufCreateInfo.size,
    -
    15760  bufCreateInfo.usage,
    -
    15761  bufCreateInfo.sharingMode,
    -
    15762  allocCreateInfo.flags,
    -
    15763  allocCreateInfo.usage,
    -
    15764  allocCreateInfo.requiredFlags,
    -
    15765  allocCreateInfo.preferredFlags,
    -
    15766  allocCreateInfo.memoryTypeBits,
    -
    15767  allocCreateInfo.pool,
    -
    15768  allocation,
    -
    15769  userDataStr.GetString());
    -
    15770  Flush();
    -
    15771 }
    -
    15772 
    -
    15773 void VmaRecorder::RecordCreateImage(uint32_t frameIndex,
    -
    15774  const VkImageCreateInfo& imageCreateInfo,
    -
    15775  const VmaAllocationCreateInfo& allocCreateInfo,
    -
    15776  VmaAllocation allocation)
    -
    15777 {
    -
    15778  CallParams callParams;
    -
    15779  GetBasicParams(callParams);
    -
    15780 
    -
    15781  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15782  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
    -
    15783  fprintf(m_File, "%u,%.3f,%u,vmaCreateImage,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15784  imageCreateInfo.flags,
    -
    15785  imageCreateInfo.imageType,
    -
    15786  imageCreateInfo.format,
    -
    15787  imageCreateInfo.extent.width,
    -
    15788  imageCreateInfo.extent.height,
    -
    15789  imageCreateInfo.extent.depth,
    -
    15790  imageCreateInfo.mipLevels,
    -
    15791  imageCreateInfo.arrayLayers,
    -
    15792  imageCreateInfo.samples,
    -
    15793  imageCreateInfo.tiling,
    -
    15794  imageCreateInfo.usage,
    -
    15795  imageCreateInfo.sharingMode,
    -
    15796  imageCreateInfo.initialLayout,
    -
    15797  allocCreateInfo.flags,
    -
    15798  allocCreateInfo.usage,
    -
    15799  allocCreateInfo.requiredFlags,
    -
    15800  allocCreateInfo.preferredFlags,
    -
    15801  allocCreateInfo.memoryTypeBits,
    -
    15802  allocCreateInfo.pool,
    -
    15803  allocation,
    -
    15804  userDataStr.GetString());
    -
    15805  Flush();
    -
    15806 }
    -
    15807 
    -
    15808 void VmaRecorder::RecordDestroyBuffer(uint32_t frameIndex,
    -
    15809  VmaAllocation allocation)
    -
    15810 {
    -
    15811  CallParams callParams;
    -
    15812  GetBasicParams(callParams);
    -
    15813 
    -
    15814  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15815  fprintf(m_File, "%u,%.3f,%u,vmaDestroyBuffer,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15816  allocation);
    -
    15817  Flush();
    -
    15818 }
    -
    15819 
    -
    15820 void VmaRecorder::RecordDestroyImage(uint32_t frameIndex,
    -
    15821  VmaAllocation allocation)
    -
    15822 {
    -
    15823  CallParams callParams;
    -
    15824  GetBasicParams(callParams);
    -
    15825 
    -
    15826  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15827  fprintf(m_File, "%u,%.3f,%u,vmaDestroyImage,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15828  allocation);
    -
    15829  Flush();
    -
    15830 }
    -
    15831 
    -
    15832 void VmaRecorder::RecordTouchAllocation(uint32_t frameIndex,
    -
    15833  VmaAllocation allocation)
    -
    15834 {
    -
    15835  CallParams callParams;
    -
    15836  GetBasicParams(callParams);
    -
    15837 
    -
    15838  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15839  fprintf(m_File, "%u,%.3f,%u,vmaTouchAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15840  allocation);
    -
    15841  Flush();
    -
    15842 }
    -
    15843 
    -
    15844 void VmaRecorder::RecordGetAllocationInfo(uint32_t frameIndex,
    -
    15845  VmaAllocation allocation)
    -
    15846 {
    -
    15847  CallParams callParams;
    -
    15848  GetBasicParams(callParams);
    -
    15849 
    -
    15850  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15851  fprintf(m_File, "%u,%.3f,%u,vmaGetAllocationInfo,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15852  allocation);
    -
    15853  Flush();
    -
    15854 }
    -
    15855 
    -
    15856 void VmaRecorder::RecordMakePoolAllocationsLost(uint32_t frameIndex,
    -
    15857  VmaPool pool)
    -
    15858 {
    -
    15859  CallParams callParams;
    -
    15860  GetBasicParams(callParams);
    -
    15861 
    -
    15862  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15863  fprintf(m_File, "%u,%.3f,%u,vmaMakePoolAllocationsLost,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15864  pool);
    -
    15865  Flush();
    -
    15866 }
    -
    15867 
    -
    15868 void VmaRecorder::RecordDefragmentationBegin(uint32_t frameIndex,
    -
    15869  const VmaDefragmentationInfo2& info,
    -
    15870  VmaDefragmentationContext ctx)
    -
    15871 {
    -
    15872  CallParams callParams;
    -
    15873  GetBasicParams(callParams);
    -
    15874 
    -
    15875  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15876  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationBegin,%u,", callParams.threadId, callParams.time, frameIndex,
    -
    15877  info.flags);
    -
    15878  PrintPointerList(info.allocationCount, info.pAllocations);
    -
    15879  fprintf(m_File, ",");
    -
    15880  PrintPointerList(info.poolCount, info.pPools);
    -
    15881  fprintf(m_File, ",%llu,%u,%llu,%u,%p,%p\n",
    -
    15882  info.maxCpuBytesToMove,
    -
    15883  info.maxCpuAllocationsToMove,
    -
    15884  info.maxGpuBytesToMove,
    -
    15885  info.maxGpuAllocationsToMove,
    -
    15886  info.commandBuffer,
    -
    15887  ctx);
    -
    15888  Flush();
    -
    15889 }
    -
    15890 
    -
    15891 void VmaRecorder::RecordDefragmentationEnd(uint32_t frameIndex,
    -
    15892  VmaDefragmentationContext ctx)
    -
    15893 {
    -
    15894  CallParams callParams;
    -
    15895  GetBasicParams(callParams);
    -
    15896 
    -
    15897  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15898  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationEnd,%p\n", callParams.threadId, callParams.time, frameIndex,
    -
    15899  ctx);
    -
    15900  Flush();
    -
    15901 }
    -
    15902 
    -
    15903 void VmaRecorder::RecordSetPoolName(uint32_t frameIndex,
    -
    15904  VmaPool pool,
    -
    15905  const char* name)
    -
    15906 {
    -
    15907  CallParams callParams;
    -
    15908  GetBasicParams(callParams);
    -
    15909 
    -
    15910  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    -
    15911  fprintf(m_File, "%u,%.3f,%u,vmaSetPoolName,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    -
    15912  pool, name != VMA_NULL ? name : "");
    -
    15913  Flush();
    -
    15914 }
    -
    15915 
    -
    15916 VmaRecorder::UserDataString::UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData)
    -
    15917 {
    -
    15918  if(pUserData != VMA_NULL)
    -
    15919  {
    -
    15920  if((allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0)
    -
    15921  {
    -
    15922  m_Str = (const char*)pUserData;
    -
    15923  }
    -
    15924  else
    -
    15925  {
    -
    15926  // If VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is not specified, convert the string's memory address to a string and store it.
    -
    15927  snprintf(m_PtrStr, 17, "%p", pUserData);
    -
    15928  m_Str = m_PtrStr;
    -
    15929  }
    -
    15930  }
    -
    15931  else
    -
    15932  {
    -
    15933  m_Str = "";
    -
    15934  }
    -
    15935 }
    -
    15936 
    -
    15937 void VmaRecorder::WriteConfiguration(
    -
    15938  const VkPhysicalDeviceProperties& devProps,
    -
    15939  const VkPhysicalDeviceMemoryProperties& memProps,
    -
    15940  uint32_t vulkanApiVersion,
    -
    15941  bool dedicatedAllocationExtensionEnabled,
    -
    15942  bool bindMemory2ExtensionEnabled,
    -
    15943  bool memoryBudgetExtensionEnabled,
    -
    15944  bool deviceCoherentMemoryExtensionEnabled)
    -
    15945 {
    -
    15946  fprintf(m_File, "Config,Begin\n");
    -
    15947 
    -
    15948  fprintf(m_File, "VulkanApiVersion,%u,%u\n", VK_VERSION_MAJOR(vulkanApiVersion), VK_VERSION_MINOR(vulkanApiVersion));
    -
    15949 
    -
    15950  fprintf(m_File, "PhysicalDevice,apiVersion,%u\n", devProps.apiVersion);
    -
    15951  fprintf(m_File, "PhysicalDevice,driverVersion,%u\n", devProps.driverVersion);
    -
    15952  fprintf(m_File, "PhysicalDevice,vendorID,%u\n", devProps.vendorID);
    -
    15953  fprintf(m_File, "PhysicalDevice,deviceID,%u\n", devProps.deviceID);
    -
    15954  fprintf(m_File, "PhysicalDevice,deviceType,%u\n", devProps.deviceType);
    -
    15955  fprintf(m_File, "PhysicalDevice,deviceName,%s\n", devProps.deviceName);
    -
    15956 
    -
    15957  fprintf(m_File, "PhysicalDeviceLimits,maxMemoryAllocationCount,%u\n", devProps.limits.maxMemoryAllocationCount);
    -
    15958  fprintf(m_File, "PhysicalDeviceLimits,bufferImageGranularity,%llu\n", devProps.limits.bufferImageGranularity);
    -
    15959  fprintf(m_File, "PhysicalDeviceLimits,nonCoherentAtomSize,%llu\n", devProps.limits.nonCoherentAtomSize);
    -
    15960 
    -
    15961  fprintf(m_File, "PhysicalDeviceMemory,HeapCount,%u\n", memProps.memoryHeapCount);
    -
    15962  for(uint32_t i = 0; i < memProps.memoryHeapCount; ++i)
    -
    15963  {
    -
    15964  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,size,%llu\n", i, memProps.memoryHeaps[i].size);
    -
    15965  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,flags,%u\n", i, memProps.memoryHeaps[i].flags);
    -
    15966  }
    -
    15967  fprintf(m_File, "PhysicalDeviceMemory,TypeCount,%u\n", memProps.memoryTypeCount);
    -
    15968  for(uint32_t i = 0; i < memProps.memoryTypeCount; ++i)
    -
    15969  {
    -
    15970  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,heapIndex,%u\n", i, memProps.memoryTypes[i].heapIndex);
    -
    15971  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,propertyFlags,%u\n", i, memProps.memoryTypes[i].propertyFlags);
    -
    15972  }
    -
    15973 
    -
    15974  fprintf(m_File, "Extension,VK_KHR_dedicated_allocation,%u\n", dedicatedAllocationExtensionEnabled ? 1 : 0);
    -
    15975  fprintf(m_File, "Extension,VK_KHR_bind_memory2,%u\n", bindMemory2ExtensionEnabled ? 1 : 0);
    -
    15976  fprintf(m_File, "Extension,VK_EXT_memory_budget,%u\n", memoryBudgetExtensionEnabled ? 1 : 0);
    -
    15977  fprintf(m_File, "Extension,VK_AMD_device_coherent_memory,%u\n", deviceCoherentMemoryExtensionEnabled ? 1 : 0);
    -
    15978 
    -
    15979  fprintf(m_File, "Macro,VMA_DEBUG_ALWAYS_DEDICATED_MEMORY,%u\n", VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ? 1 : 0);
    -
    15980  fprintf(m_File, "Macro,VMA_MIN_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_MIN_ALIGNMENT);
    -
    15981  fprintf(m_File, "Macro,VMA_DEBUG_MARGIN,%llu\n", (VkDeviceSize)VMA_DEBUG_MARGIN);
    -
    15982  fprintf(m_File, "Macro,VMA_DEBUG_INITIALIZE_ALLOCATIONS,%u\n", VMA_DEBUG_INITIALIZE_ALLOCATIONS ? 1 : 0);
    -
    15983  fprintf(m_File, "Macro,VMA_DEBUG_DETECT_CORRUPTION,%u\n", VMA_DEBUG_DETECT_CORRUPTION ? 1 : 0);
    -
    15984  fprintf(m_File, "Macro,VMA_DEBUG_GLOBAL_MUTEX,%u\n", VMA_DEBUG_GLOBAL_MUTEX ? 1 : 0);
    -
    15985  fprintf(m_File, "Macro,VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY,%llu\n", (VkDeviceSize)VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY);
    -
    15986  fprintf(m_File, "Macro,VMA_SMALL_HEAP_MAX_SIZE,%llu\n", (VkDeviceSize)VMA_SMALL_HEAP_MAX_SIZE);
    -
    15987  fprintf(m_File, "Macro,VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE,%llu\n", (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
    +
    15508 void VmaRecorder::RecordDestroyAllocator(uint32_t frameIndex)
    +
    15509 {
    +
    15510  CallParams callParams;
    +
    15511  GetBasicParams(callParams);
    +
    15512 
    +
    15513  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15514  fprintf(m_File, "%u,%.3f,%u,vmaDestroyAllocator\n", callParams.threadId, callParams.time, frameIndex);
    +
    15515  Flush();
    +
    15516 }
    +
    15517 
    +
    15518 void VmaRecorder::RecordCreatePool(uint32_t frameIndex, const VmaPoolCreateInfo& createInfo, VmaPool pool)
    +
    15519 {
    +
    15520  CallParams callParams;
    +
    15521  GetBasicParams(callParams);
    +
    15522 
    +
    15523  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15524  fprintf(m_File, "%u,%.3f,%u,vmaCreatePool,%u,%u,%llu,%llu,%llu,%u,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15525  createInfo.memoryTypeIndex,
    +
    15526  createInfo.flags,
    +
    15527  createInfo.blockSize,
    +
    15528  (uint64_t)createInfo.minBlockCount,
    +
    15529  (uint64_t)createInfo.maxBlockCount,
    +
    15530  createInfo.frameInUseCount,
    +
    15531  pool);
    +
    15532  Flush();
    +
    15533 }
    +
    15534 
    +
    15535 void VmaRecorder::RecordDestroyPool(uint32_t frameIndex, VmaPool pool)
    +
    15536 {
    +
    15537  CallParams callParams;
    +
    15538  GetBasicParams(callParams);
    +
    15539 
    +
    15540  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15541  fprintf(m_File, "%u,%.3f,%u,vmaDestroyPool,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15542  pool);
    +
    15543  Flush();
    +
    15544 }
    +
    15545 
    +
    15546 void VmaRecorder::RecordAllocateMemory(uint32_t frameIndex,
    +
    15547  const VkMemoryRequirements& vkMemReq,
    +
    15548  const VmaAllocationCreateInfo& createInfo,
    +
    15549  VmaAllocation allocation)
    +
    15550 {
    +
    15551  CallParams callParams;
    +
    15552  GetBasicParams(callParams);
    +
    15553 
    +
    15554  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15555  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    +
    15556  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemory,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15557  vkMemReq.size,
    +
    15558  vkMemReq.alignment,
    +
    15559  vkMemReq.memoryTypeBits,
    +
    15560  createInfo.flags,
    +
    15561  createInfo.usage,
    +
    15562  createInfo.requiredFlags,
    +
    15563  createInfo.preferredFlags,
    +
    15564  createInfo.memoryTypeBits,
    +
    15565  createInfo.pool,
    +
    15566  allocation,
    +
    15567  userDataStr.GetString());
    +
    15568  Flush();
    +
    15569 }
    +
    15570 
    +
    15571 void VmaRecorder::RecordAllocateMemoryPages(uint32_t frameIndex,
    +
    15572  const VkMemoryRequirements& vkMemReq,
    +
    15573  const VmaAllocationCreateInfo& createInfo,
    +
    15574  uint64_t allocationCount,
    +
    15575  const VmaAllocation* pAllocations)
    +
    15576 {
    +
    15577  CallParams callParams;
    +
    15578  GetBasicParams(callParams);
    +
    15579 
    +
    15580  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15581  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    +
    15582  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryPages,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,", callParams.threadId, callParams.time, frameIndex,
    +
    15583  vkMemReq.size,
    +
    15584  vkMemReq.alignment,
    +
    15585  vkMemReq.memoryTypeBits,
    +
    15586  createInfo.flags,
    +
    15587  createInfo.usage,
    +
    15588  createInfo.requiredFlags,
    +
    15589  createInfo.preferredFlags,
    +
    15590  createInfo.memoryTypeBits,
    +
    15591  createInfo.pool);
    +
    15592  PrintPointerList(allocationCount, pAllocations);
    +
    15593  fprintf(m_File, ",%s\n", userDataStr.GetString());
    +
    15594  Flush();
    +
    15595 }
    +
    15596 
    +
    15597 void VmaRecorder::RecordAllocateMemoryForBuffer(uint32_t frameIndex,
    +
    15598  const VkMemoryRequirements& vkMemReq,
    +
    15599  bool requiresDedicatedAllocation,
    +
    15600  bool prefersDedicatedAllocation,
    +
    15601  const VmaAllocationCreateInfo& createInfo,
    +
    15602  VmaAllocation allocation)
    +
    15603 {
    +
    15604  CallParams callParams;
    +
    15605  GetBasicParams(callParams);
    +
    15606 
    +
    15607  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15608  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    +
    15609  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForBuffer,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15610  vkMemReq.size,
    +
    15611  vkMemReq.alignment,
    +
    15612  vkMemReq.memoryTypeBits,
    +
    15613  requiresDedicatedAllocation ? 1 : 0,
    +
    15614  prefersDedicatedAllocation ? 1 : 0,
    +
    15615  createInfo.flags,
    +
    15616  createInfo.usage,
    +
    15617  createInfo.requiredFlags,
    +
    15618  createInfo.preferredFlags,
    +
    15619  createInfo.memoryTypeBits,
    +
    15620  createInfo.pool,
    +
    15621  allocation,
    +
    15622  userDataStr.GetString());
    +
    15623  Flush();
    +
    15624 }
    +
    15625 
    +
    15626 void VmaRecorder::RecordAllocateMemoryForImage(uint32_t frameIndex,
    +
    15627  const VkMemoryRequirements& vkMemReq,
    +
    15628  bool requiresDedicatedAllocation,
    +
    15629  bool prefersDedicatedAllocation,
    +
    15630  const VmaAllocationCreateInfo& createInfo,
    +
    15631  VmaAllocation allocation)
    +
    15632 {
    +
    15633  CallParams callParams;
    +
    15634  GetBasicParams(callParams);
    +
    15635 
    +
    15636  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15637  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
    +
    15638  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForImage,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15639  vkMemReq.size,
    +
    15640  vkMemReq.alignment,
    +
    15641  vkMemReq.memoryTypeBits,
    +
    15642  requiresDedicatedAllocation ? 1 : 0,
    +
    15643  prefersDedicatedAllocation ? 1 : 0,
    +
    15644  createInfo.flags,
    +
    15645  createInfo.usage,
    +
    15646  createInfo.requiredFlags,
    +
    15647  createInfo.preferredFlags,
    +
    15648  createInfo.memoryTypeBits,
    +
    15649  createInfo.pool,
    +
    15650  allocation,
    +
    15651  userDataStr.GetString());
    +
    15652  Flush();
    +
    15653 }
    +
    15654 
    +
    15655 void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
    +
    15656  VmaAllocation allocation)
    +
    15657 {
    +
    15658  CallParams callParams;
    +
    15659  GetBasicParams(callParams);
    +
    15660 
    +
    15661  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15662  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15663  allocation);
    +
    15664  Flush();
    +
    15665 }
    +
    15666 
    +
    15667 void VmaRecorder::RecordFreeMemoryPages(uint32_t frameIndex,
    +
    15668  uint64_t allocationCount,
    +
    15669  const VmaAllocation* pAllocations)
    +
    15670 {
    +
    15671  CallParams callParams;
    +
    15672  GetBasicParams(callParams);
    +
    15673 
    +
    15674  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15675  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemoryPages,", callParams.threadId, callParams.time, frameIndex);
    +
    15676  PrintPointerList(allocationCount, pAllocations);
    +
    15677  fprintf(m_File, "\n");
    +
    15678  Flush();
    +
    15679 }
    +
    15680 
    +
    15681 void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
    +
    15682  VmaAllocation allocation,
    +
    15683  const void* pUserData)
    +
    15684 {
    +
    15685  CallParams callParams;
    +
    15686  GetBasicParams(callParams);
    +
    15687 
    +
    15688  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15689  UserDataString userDataStr(
    +
    15690  allocation->IsUserDataString() ? VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT : 0,
    +
    15691  pUserData);
    +
    15692  fprintf(m_File, "%u,%.3f,%u,vmaSetAllocationUserData,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15693  allocation,
    +
    15694  userDataStr.GetString());
    +
    15695  Flush();
    +
    15696 }
    +
    15697 
    +
    15698 void VmaRecorder::RecordCreateLostAllocation(uint32_t frameIndex,
    +
    15699  VmaAllocation allocation)
    +
    15700 {
    +
    15701  CallParams callParams;
    +
    15702  GetBasicParams(callParams);
    +
    15703 
    +
    15704  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15705  fprintf(m_File, "%u,%.3f,%u,vmaCreateLostAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15706  allocation);
    +
    15707  Flush();
    +
    15708 }
    +
    15709 
    +
    15710 void VmaRecorder::RecordMapMemory(uint32_t frameIndex,
    +
    15711  VmaAllocation allocation)
    +
    15712 {
    +
    15713  CallParams callParams;
    +
    15714  GetBasicParams(callParams);
    +
    15715 
    +
    15716  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15717  fprintf(m_File, "%u,%.3f,%u,vmaMapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15718  allocation);
    +
    15719  Flush();
    +
    15720 }
    +
    15721 
    +
    15722 void VmaRecorder::RecordUnmapMemory(uint32_t frameIndex,
    +
    15723  VmaAllocation allocation)
    +
    15724 {
    +
    15725  CallParams callParams;
    +
    15726  GetBasicParams(callParams);
    +
    15727 
    +
    15728  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15729  fprintf(m_File, "%u,%.3f,%u,vmaUnmapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15730  allocation);
    +
    15731  Flush();
    +
    15732 }
    +
    15733 
    +
    15734 void VmaRecorder::RecordFlushAllocation(uint32_t frameIndex,
    +
    15735  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    +
    15736 {
    +
    15737  CallParams callParams;
    +
    15738  GetBasicParams(callParams);
    +
    15739 
    +
    15740  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15741  fprintf(m_File, "%u,%.3f,%u,vmaFlushAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
    +
    15742  allocation,
    +
    15743  offset,
    +
    15744  size);
    +
    15745  Flush();
    +
    15746 }
    +
    15747 
    +
    15748 void VmaRecorder::RecordInvalidateAllocation(uint32_t frameIndex,
    +
    15749  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    +
    15750 {
    +
    15751  CallParams callParams;
    +
    15752  GetBasicParams(callParams);
    +
    15753 
    +
    15754  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15755  fprintf(m_File, "%u,%.3f,%u,vmaInvalidateAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
    +
    15756  allocation,
    +
    15757  offset,
    +
    15758  size);
    +
    15759  Flush();
    +
    15760 }
    +
    15761 
    +
    15762 void VmaRecorder::RecordCreateBuffer(uint32_t frameIndex,
    +
    15763  const VkBufferCreateInfo& bufCreateInfo,
    +
    15764  const VmaAllocationCreateInfo& allocCreateInfo,
    +
    15765  VmaAllocation allocation)
    +
    15766 {
    +
    15767  CallParams callParams;
    +
    15768  GetBasicParams(callParams);
    +
    15769 
    +
    15770  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15771  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
    +
    15772  fprintf(m_File, "%u,%.3f,%u,vmaCreateBuffer,%u,%llu,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15773  bufCreateInfo.flags,
    +
    15774  bufCreateInfo.size,
    +
    15775  bufCreateInfo.usage,
    +
    15776  bufCreateInfo.sharingMode,
    +
    15777  allocCreateInfo.flags,
    +
    15778  allocCreateInfo.usage,
    +
    15779  allocCreateInfo.requiredFlags,
    +
    15780  allocCreateInfo.preferredFlags,
    +
    15781  allocCreateInfo.memoryTypeBits,
    +
    15782  allocCreateInfo.pool,
    +
    15783  allocation,
    +
    15784  userDataStr.GetString());
    +
    15785  Flush();
    +
    15786 }
    +
    15787 
    +
    15788 void VmaRecorder::RecordCreateImage(uint32_t frameIndex,
    +
    15789  const VkImageCreateInfo& imageCreateInfo,
    +
    15790  const VmaAllocationCreateInfo& allocCreateInfo,
    +
    15791  VmaAllocation allocation)
    +
    15792 {
    +
    15793  CallParams callParams;
    +
    15794  GetBasicParams(callParams);
    +
    15795 
    +
    15796  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15797  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
    +
    15798  fprintf(m_File, "%u,%.3f,%u,vmaCreateImage,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15799  imageCreateInfo.flags,
    +
    15800  imageCreateInfo.imageType,
    +
    15801  imageCreateInfo.format,
    +
    15802  imageCreateInfo.extent.width,
    +
    15803  imageCreateInfo.extent.height,
    +
    15804  imageCreateInfo.extent.depth,
    +
    15805  imageCreateInfo.mipLevels,
    +
    15806  imageCreateInfo.arrayLayers,
    +
    15807  imageCreateInfo.samples,
    +
    15808  imageCreateInfo.tiling,
    +
    15809  imageCreateInfo.usage,
    +
    15810  imageCreateInfo.sharingMode,
    +
    15811  imageCreateInfo.initialLayout,
    +
    15812  allocCreateInfo.flags,
    +
    15813  allocCreateInfo.usage,
    +
    15814  allocCreateInfo.requiredFlags,
    +
    15815  allocCreateInfo.preferredFlags,
    +
    15816  allocCreateInfo.memoryTypeBits,
    +
    15817  allocCreateInfo.pool,
    +
    15818  allocation,
    +
    15819  userDataStr.GetString());
    +
    15820  Flush();
    +
    15821 }
    +
    15822 
    +
    15823 void VmaRecorder::RecordDestroyBuffer(uint32_t frameIndex,
    +
    15824  VmaAllocation allocation)
    +
    15825 {
    +
    15826  CallParams callParams;
    +
    15827  GetBasicParams(callParams);
    +
    15828 
    +
    15829  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15830  fprintf(m_File, "%u,%.3f,%u,vmaDestroyBuffer,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15831  allocation);
    +
    15832  Flush();
    +
    15833 }
    +
    15834 
    +
    15835 void VmaRecorder::RecordDestroyImage(uint32_t frameIndex,
    +
    15836  VmaAllocation allocation)
    +
    15837 {
    +
    15838  CallParams callParams;
    +
    15839  GetBasicParams(callParams);
    +
    15840 
    +
    15841  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15842  fprintf(m_File, "%u,%.3f,%u,vmaDestroyImage,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15843  allocation);
    +
    15844  Flush();
    +
    15845 }
    +
    15846 
    +
    15847 void VmaRecorder::RecordTouchAllocation(uint32_t frameIndex,
    +
    15848  VmaAllocation allocation)
    +
    15849 {
    +
    15850  CallParams callParams;
    +
    15851  GetBasicParams(callParams);
    +
    15852 
    +
    15853  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15854  fprintf(m_File, "%u,%.3f,%u,vmaTouchAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15855  allocation);
    +
    15856  Flush();
    +
    15857 }
    +
    15858 
    +
    15859 void VmaRecorder::RecordGetAllocationInfo(uint32_t frameIndex,
    +
    15860  VmaAllocation allocation)
    +
    15861 {
    +
    15862  CallParams callParams;
    +
    15863  GetBasicParams(callParams);
    +
    15864 
    +
    15865  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15866  fprintf(m_File, "%u,%.3f,%u,vmaGetAllocationInfo,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15867  allocation);
    +
    15868  Flush();
    +
    15869 }
    +
    15870 
    +
    15871 void VmaRecorder::RecordMakePoolAllocationsLost(uint32_t frameIndex,
    +
    15872  VmaPool pool)
    +
    15873 {
    +
    15874  CallParams callParams;
    +
    15875  GetBasicParams(callParams);
    +
    15876 
    +
    15877  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15878  fprintf(m_File, "%u,%.3f,%u,vmaMakePoolAllocationsLost,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15879  pool);
    +
    15880  Flush();
    +
    15881 }
    +
    15882 
    +
    15883 void VmaRecorder::RecordDefragmentationBegin(uint32_t frameIndex,
    +
    15884  const VmaDefragmentationInfo2& info,
    +
    15885  VmaDefragmentationContext ctx)
    +
    15886 {
    +
    15887  CallParams callParams;
    +
    15888  GetBasicParams(callParams);
    +
    15889 
    +
    15890  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15891  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationBegin,%u,", callParams.threadId, callParams.time, frameIndex,
    +
    15892  info.flags);
    +
    15893  PrintPointerList(info.allocationCount, info.pAllocations);
    +
    15894  fprintf(m_File, ",");
    +
    15895  PrintPointerList(info.poolCount, info.pPools);
    +
    15896  fprintf(m_File, ",%llu,%u,%llu,%u,%p,%p\n",
    +
    15897  info.maxCpuBytesToMove,
    +
    15898  info.maxCpuAllocationsToMove,
    +
    15899  info.maxGpuBytesToMove,
    +
    15900  info.maxGpuAllocationsToMove,
    +
    15901  info.commandBuffer,
    +
    15902  ctx);
    +
    15903  Flush();
    +
    15904 }
    +
    15905 
    +
    15906 void VmaRecorder::RecordDefragmentationEnd(uint32_t frameIndex,
    +
    15907  VmaDefragmentationContext ctx)
    +
    15908 {
    +
    15909  CallParams callParams;
    +
    15910  GetBasicParams(callParams);
    +
    15911 
    +
    15912  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15913  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationEnd,%p\n", callParams.threadId, callParams.time, frameIndex,
    +
    15914  ctx);
    +
    15915  Flush();
    +
    15916 }
    +
    15917 
    +
    15918 void VmaRecorder::RecordSetPoolName(uint32_t frameIndex,
    +
    15919  VmaPool pool,
    +
    15920  const char* name)
    +
    15921 {
    +
    15922  CallParams callParams;
    +
    15923  GetBasicParams(callParams);
    +
    15924 
    +
    15925  VmaMutexLock lock(m_FileMutex, m_UseMutex);
    +
    15926  fprintf(m_File, "%u,%.3f,%u,vmaSetPoolName,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
    +
    15927  pool, name != VMA_NULL ? name : "");
    +
    15928  Flush();
    +
    15929 }
    +
    15930 
    +
    15931 VmaRecorder::UserDataString::UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData)
    +
    15932 {
    +
    15933  if(pUserData != VMA_NULL)
    +
    15934  {
    +
    15935  if((allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0)
    +
    15936  {
    +
    15937  m_Str = (const char*)pUserData;
    +
    15938  }
    +
    15939  else
    +
    15940  {
    +
    15941  // If VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is not specified, convert the string's memory address to a string and store it.
    +
    15942  snprintf(m_PtrStr, 17, "%p", pUserData);
    +
    15943  m_Str = m_PtrStr;
    +
    15944  }
    +
    15945  }
    +
    15946  else
    +
    15947  {
    +
    15948  m_Str = "";
    +
    15949  }
    +
    15950 }
    +
    15951 
    +
    15952 void VmaRecorder::WriteConfiguration(
    +
    15953  const VkPhysicalDeviceProperties& devProps,
    +
    15954  const VkPhysicalDeviceMemoryProperties& memProps,
    +
    15955  uint32_t vulkanApiVersion,
    +
    15956  bool dedicatedAllocationExtensionEnabled,
    +
    15957  bool bindMemory2ExtensionEnabled,
    +
    15958  bool memoryBudgetExtensionEnabled,
    +
    15959  bool deviceCoherentMemoryExtensionEnabled)
    +
    15960 {
    +
    15961  fprintf(m_File, "Config,Begin\n");
    +
    15962 
    +
    15963  fprintf(m_File, "VulkanApiVersion,%u,%u\n", VK_VERSION_MAJOR(vulkanApiVersion), VK_VERSION_MINOR(vulkanApiVersion));
    +
    15964 
    +
    15965  fprintf(m_File, "PhysicalDevice,apiVersion,%u\n", devProps.apiVersion);
    +
    15966  fprintf(m_File, "PhysicalDevice,driverVersion,%u\n", devProps.driverVersion);
    +
    15967  fprintf(m_File, "PhysicalDevice,vendorID,%u\n", devProps.vendorID);
    +
    15968  fprintf(m_File, "PhysicalDevice,deviceID,%u\n", devProps.deviceID);
    +
    15969  fprintf(m_File, "PhysicalDevice,deviceType,%u\n", devProps.deviceType);
    +
    15970  fprintf(m_File, "PhysicalDevice,deviceName,%s\n", devProps.deviceName);
    +
    15971 
    +
    15972  fprintf(m_File, "PhysicalDeviceLimits,maxMemoryAllocationCount,%u\n", devProps.limits.maxMemoryAllocationCount);
    +
    15973  fprintf(m_File, "PhysicalDeviceLimits,bufferImageGranularity,%llu\n", devProps.limits.bufferImageGranularity);
    +
    15974  fprintf(m_File, "PhysicalDeviceLimits,nonCoherentAtomSize,%llu\n", devProps.limits.nonCoherentAtomSize);
    +
    15975 
    +
    15976  fprintf(m_File, "PhysicalDeviceMemory,HeapCount,%u\n", memProps.memoryHeapCount);
    +
    15977  for(uint32_t i = 0; i < memProps.memoryHeapCount; ++i)
    +
    15978  {
    +
    15979  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,size,%llu\n", i, memProps.memoryHeaps[i].size);
    +
    15980  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,flags,%u\n", i, memProps.memoryHeaps[i].flags);
    +
    15981  }
    +
    15982  fprintf(m_File, "PhysicalDeviceMemory,TypeCount,%u\n", memProps.memoryTypeCount);
    +
    15983  for(uint32_t i = 0; i < memProps.memoryTypeCount; ++i)
    +
    15984  {
    +
    15985  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,heapIndex,%u\n", i, memProps.memoryTypes[i].heapIndex);
    +
    15986  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,propertyFlags,%u\n", i, memProps.memoryTypes[i].propertyFlags);
    +
    15987  }
    15988 
    -
    15989  fprintf(m_File, "Config,End\n");
    -
    15990 }
    -
    15991 
    -
    15992 void VmaRecorder::GetBasicParams(CallParams& outParams)
    -
    15993 {
    -
    15994  #if defined(_WIN32)
    -
    15995  outParams.threadId = GetCurrentThreadId();
    -
    15996  #else
    -
    15997  // Use C++11 features to get thread id and convert it to uint32_t.
    -
    15998  // There is room for optimization since sstream is quite slow.
    -
    15999  // Is there a better way to convert std::this_thread::get_id() to uint32_t?
    -
    16000  std::thread::id thread_id = std::this_thread::get_id();
    -
    16001  std::stringstream thread_id_to_string_converter;
    -
    16002  thread_id_to_string_converter << thread_id;
    -
    16003  std::string thread_id_as_string = thread_id_to_string_converter.str();
    -
    16004  outParams.threadId = static_cast<uint32_t>(std::stoi(thread_id_as_string.c_str()));
    -
    16005  #endif
    +
    15989  fprintf(m_File, "Extension,VK_KHR_dedicated_allocation,%u\n", dedicatedAllocationExtensionEnabled ? 1 : 0);
    +
    15990  fprintf(m_File, "Extension,VK_KHR_bind_memory2,%u\n", bindMemory2ExtensionEnabled ? 1 : 0);
    +
    15991  fprintf(m_File, "Extension,VK_EXT_memory_budget,%u\n", memoryBudgetExtensionEnabled ? 1 : 0);
    +
    15992  fprintf(m_File, "Extension,VK_AMD_device_coherent_memory,%u\n", deviceCoherentMemoryExtensionEnabled ? 1 : 0);
    +
    15993 
    +
    15994  fprintf(m_File, "Macro,VMA_DEBUG_ALWAYS_DEDICATED_MEMORY,%u\n", VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ? 1 : 0);
    +
    15995  fprintf(m_File, "Macro,VMA_MIN_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_MIN_ALIGNMENT);
    +
    15996  fprintf(m_File, "Macro,VMA_DEBUG_MARGIN,%llu\n", (VkDeviceSize)VMA_DEBUG_MARGIN);
    +
    15997  fprintf(m_File, "Macro,VMA_DEBUG_INITIALIZE_ALLOCATIONS,%u\n", VMA_DEBUG_INITIALIZE_ALLOCATIONS ? 1 : 0);
    +
    15998  fprintf(m_File, "Macro,VMA_DEBUG_DETECT_CORRUPTION,%u\n", VMA_DEBUG_DETECT_CORRUPTION ? 1 : 0);
    +
    15999  fprintf(m_File, "Macro,VMA_DEBUG_GLOBAL_MUTEX,%u\n", VMA_DEBUG_GLOBAL_MUTEX ? 1 : 0);
    +
    16000  fprintf(m_File, "Macro,VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY,%llu\n", (VkDeviceSize)VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY);
    +
    16001  fprintf(m_File, "Macro,VMA_SMALL_HEAP_MAX_SIZE,%llu\n", (VkDeviceSize)VMA_SMALL_HEAP_MAX_SIZE);
    +
    16002  fprintf(m_File, "Macro,VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE,%llu\n", (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
    +
    16003 
    +
    16004  fprintf(m_File, "Config,End\n");
    +
    16005 }
    16006 
    -
    16007  auto current_time = std::chrono::high_resolution_clock::now();
    -
    16008 
    -
    16009  outParams.time = std::chrono::duration<double, std::chrono::seconds::period>(current_time - m_RecordingStartTime).count();
    -
    16010 }
    -
    16011 
    -
    16012 void VmaRecorder::PrintPointerList(uint64_t count, const VmaAllocation* pItems)
    -
    16013 {
    -
    16014  if(count)
    -
    16015  {
    -
    16016  fprintf(m_File, "%p", pItems[0]);
    -
    16017  for(uint64_t i = 1; i < count; ++i)
    -
    16018  {
    -
    16019  fprintf(m_File, " %p", pItems[i]);
    -
    16020  }
    -
    16021  }
    -
    16022 }
    +
    16007 void VmaRecorder::GetBasicParams(CallParams& outParams)
    +
    16008 {
    +
    16009  #if defined(_WIN32)
    +
    16010  outParams.threadId = GetCurrentThreadId();
    +
    16011  #else
    +
    16012  // Use C++11 features to get thread id and convert it to uint32_t.
    +
    16013  // There is room for optimization since sstream is quite slow.
    +
    16014  // Is there a better way to convert std::this_thread::get_id() to uint32_t?
    +
    16015  std::thread::id thread_id = std::this_thread::get_id();
    +
    16016  std::stringstream thread_id_to_string_converter;
    +
    16017  thread_id_to_string_converter << thread_id;
    +
    16018  std::string thread_id_as_string = thread_id_to_string_converter.str();
    +
    16019  outParams.threadId = static_cast<uint32_t>(std::stoi(thread_id_as_string.c_str()));
    +
    16020  #endif
    +
    16021 
    +
    16022  auto current_time = std::chrono::high_resolution_clock::now();
    16023 
    -
    16024 void VmaRecorder::Flush()
    -
    16025 {
    -
    16026  if((m_Flags & VMA_RECORD_FLUSH_AFTER_CALL_BIT) != 0)
    -
    16027  {
    -
    16028  fflush(m_File);
    -
    16029  }
    -
    16030 }
    -
    16031 
    -
    16032 #endif // #if VMA_RECORDING_ENABLED
    -
    16033 
    -
    16035 // VmaAllocationObjectAllocator
    -
    16036 
    -
    16037 VmaAllocationObjectAllocator::VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) :
    -
    16038  m_Allocator(pAllocationCallbacks, 1024)
    -
    16039 {
    -
    16040 }
    -
    16041 
    -
    16042 template<typename... Types> VmaAllocation VmaAllocationObjectAllocator::Allocate(Types... args)
    -
    16043 {
    -
    16044  VmaMutexLock mutexLock(m_Mutex);
    -
    16045  return m_Allocator.Alloc<Types...>(std::forward<Types>(args)...);
    -
    16046 }
    -
    16047 
    -
    16048 void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc)
    -
    16049 {
    -
    16050  VmaMutexLock mutexLock(m_Mutex);
    -
    16051  m_Allocator.Free(hAlloc);
    -
    16052 }
    -
    16053 
    -
    16055 // VmaAllocator_T
    +
    16024  outParams.time = std::chrono::duration<double, std::chrono::seconds::period>(current_time - m_RecordingStartTime).count();
    +
    16025 }
    +
    16026 
    +
    16027 void VmaRecorder::PrintPointerList(uint64_t count, const VmaAllocation* pItems)
    +
    16028 {
    +
    16029  if(count)
    +
    16030  {
    +
    16031  fprintf(m_File, "%p", pItems[0]);
    +
    16032  for(uint64_t i = 1; i < count; ++i)
    +
    16033  {
    +
    16034  fprintf(m_File, " %p", pItems[i]);
    +
    16035  }
    +
    16036  }
    +
    16037 }
    +
    16038 
    +
    16039 void VmaRecorder::Flush()
    +
    16040 {
    +
    16041  if((m_Flags & VMA_RECORD_FLUSH_AFTER_CALL_BIT) != 0)
    +
    16042  {
    +
    16043  fflush(m_File);
    +
    16044  }
    +
    16045 }
    +
    16046 
    +
    16047 #endif // #if VMA_RECORDING_ENABLED
    +
    16048 
    +
    16050 // VmaAllocationObjectAllocator
    +
    16051 
    +
    16052 VmaAllocationObjectAllocator::VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) :
    +
    16053  m_Allocator(pAllocationCallbacks, 1024)
    +
    16054 {
    +
    16055 }
    16056 
    -
    16057 VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
    -
    16058  m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
    -
    16059  m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0),
    -
    16060  m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0),
    -
    16061  m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0),
    -
    16062  m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0),
    -
    16063  m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0),
    -
    16064  m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0),
    -
    16065  m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
    -
    16066  m_hDevice(pCreateInfo->device),
    -
    16067  m_hInstance(pCreateInfo->instance),
    -
    16068  m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
    -
    16069  m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
    -
    16070  *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
    -
    16071  m_AllocationObjectAllocator(&m_AllocationCallbacks),
    -
    16072  m_HeapSizeLimitMask(0),
    -
    16073  m_DeviceMemoryCount(0),
    -
    16074  m_PreferredLargeHeapBlockSize(0),
    -
    16075  m_PhysicalDevice(pCreateInfo->physicalDevice),
    -
    16076  m_CurrentFrameIndex(0),
    -
    16077  m_GpuDefragmentationMemoryTypeBits(UINT32_MAX),
    -
    16078  m_NextPoolId(0),
    -
    16079  m_GlobalMemoryTypeBits(UINT32_MAX)
    -
    16080 #if VMA_RECORDING_ENABLED
    -
    16081  ,m_pRecorder(VMA_NULL)
    -
    16082 #endif
    -
    16083 {
    -
    16084  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    -
    16085  {
    -
    16086  m_UseKhrDedicatedAllocation = false;
    -
    16087  m_UseKhrBindMemory2 = false;
    -
    16088  }
    -
    16089 
    -
    16090  if(VMA_DEBUG_DETECT_CORRUPTION)
    -
    16091  {
    -
    16092  // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it.
    -
    16093  VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0);
    -
    16094  }
    -
    16095 
    -
    16096  VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance);
    -
    16097 
    -
    16098  if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0))
    -
    16099  {
    -
    16100 #if !(VMA_DEDICATED_ALLOCATION)
    -
    16101  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0)
    -
    16102  {
    -
    16103  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros.");
    -
    16104  }
    -
    16105 #endif
    -
    16106 #if !(VMA_BIND_MEMORY2)
    -
    16107  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0)
    -
    16108  {
    -
    16109  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros.");
    -
    16110  }
    -
    16111 #endif
    -
    16112  }
    -
    16113 #if !(VMA_MEMORY_BUDGET)
    -
    16114  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0)
    -
    16115  {
    -
    16116  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros.");
    -
    16117  }
    -
    16118 #endif
    -
    16119 #if !(VMA_BUFFER_DEVICE_ADDRESS)
    -
    16120  if(m_UseKhrBufferDeviceAddress)
    -
    16121  {
    -
    16122  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
    -
    16123  }
    -
    16124 #endif
    -
    16125 #if VMA_VULKAN_VERSION < 1002000
    -
    16126  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0))
    -
    16127  {
    -
    16128  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros.");
    -
    16129  }
    -
    16130 #endif
    -
    16131 #if VMA_VULKAN_VERSION < 1001000
    -
    16132  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    -
    16133  {
    -
    16134  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros.");
    -
    16135  }
    -
    16136 #endif
    -
    16137 #if !(VMA_MEMORY_PRIORITY)
    -
    16138  if(m_UseExtMemoryPriority)
    -
    16139  {
    -
    16140  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
    -
    16141  }
    -
    16142 #endif
    -
    16143 
    -
    16144  memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
    -
    16145  memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
    -
    16146  memset(&m_MemProps, 0, sizeof(m_MemProps));
    -
    16147 
    -
    16148  memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
    -
    16149  memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions));
    -
    16150 
    -
    16151 #if VMA_EXTERNAL_MEMORY
    -
    16152  memset(&m_TypeExternalMemoryHandleTypes, 0, sizeof(m_TypeExternalMemoryHandleTypes));
    -
    16153 #endif // #if VMA_EXTERNAL_MEMORY
    -
    16154 
    -
    16155  if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
    -
    16156  {
    -
    16157  m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData;
    -
    16158  m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
    -
    16159  m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
    -
    16160  }
    -
    16161 
    -
    16162  ImportVulkanFunctions(pCreateInfo->pVulkanFunctions);
    -
    16163 
    -
    16164  (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties);
    -
    16165  (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
    -
    16166 
    -
    16167  VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT));
    -
    16168  VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY));
    -
    16169  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity));
    -
    16170  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize));
    -
    16171 
    -
    16172  m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
    -
    16173  pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
    -
    16174 
    -
    16175  m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits();
    +
    16057 template<typename... Types> VmaAllocation VmaAllocationObjectAllocator::Allocate(Types... args)
    +
    16058 {
    +
    16059  VmaMutexLock mutexLock(m_Mutex);
    +
    16060  return m_Allocator.Alloc<Types...>(std::forward<Types>(args)...);
    +
    16061 }
    +
    16062 
    +
    16063 void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc)
    +
    16064 {
    +
    16065  VmaMutexLock mutexLock(m_Mutex);
    +
    16066  m_Allocator.Free(hAlloc);
    +
    16067 }
    +
    16068 
    +
    16070 // VmaAllocator_T
    +
    16071 
    +
    16072 VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
    +
    16073  m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
    +
    16074  m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0),
    +
    16075  m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0),
    +
    16076  m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0),
    +
    16077  m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0),
    +
    16078  m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0),
    +
    16079  m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0),
    +
    16080  m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
    +
    16081  m_hDevice(pCreateInfo->device),
    +
    16082  m_hInstance(pCreateInfo->instance),
    +
    16083  m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
    +
    16084  m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
    +
    16085  *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
    +
    16086  m_AllocationObjectAllocator(&m_AllocationCallbacks),
    +
    16087  m_HeapSizeLimitMask(0),
    +
    16088  m_DeviceMemoryCount(0),
    +
    16089  m_PreferredLargeHeapBlockSize(0),
    +
    16090  m_PhysicalDevice(pCreateInfo->physicalDevice),
    +
    16091  m_CurrentFrameIndex(0),
    +
    16092  m_GpuDefragmentationMemoryTypeBits(UINT32_MAX),
    +
    16093  m_NextPoolId(0),
    +
    16094  m_GlobalMemoryTypeBits(UINT32_MAX)
    +
    16095 #if VMA_RECORDING_ENABLED
    +
    16096  ,m_pRecorder(VMA_NULL)
    +
    16097 #endif
    +
    16098 {
    +
    16099  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16100  {
    +
    16101  m_UseKhrDedicatedAllocation = false;
    +
    16102  m_UseKhrBindMemory2 = false;
    +
    16103  }
    +
    16104 
    +
    16105  if(VMA_DEBUG_DETECT_CORRUPTION)
    +
    16106  {
    +
    16107  // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it.
    +
    16108  VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0);
    +
    16109  }
    +
    16110 
    +
    16111  VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance);
    +
    16112 
    +
    16113  if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0))
    +
    16114  {
    +
    16115 #if !(VMA_DEDICATED_ALLOCATION)
    +
    16116  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0)
    +
    16117  {
    +
    16118  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros.");
    +
    16119  }
    +
    16120 #endif
    +
    16121 #if !(VMA_BIND_MEMORY2)
    +
    16122  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0)
    +
    16123  {
    +
    16124  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros.");
    +
    16125  }
    +
    16126 #endif
    +
    16127  }
    +
    16128 #if !(VMA_MEMORY_BUDGET)
    +
    16129  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0)
    +
    16130  {
    +
    16131  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros.");
    +
    16132  }
    +
    16133 #endif
    +
    16134 #if !(VMA_BUFFER_DEVICE_ADDRESS)
    +
    16135  if(m_UseKhrBufferDeviceAddress)
    +
    16136  {
    +
    16137  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
    +
    16138  }
    +
    16139 #endif
    +
    16140 #if VMA_VULKAN_VERSION < 1002000
    +
    16141  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0))
    +
    16142  {
    +
    16143  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros.");
    +
    16144  }
    +
    16145 #endif
    +
    16146 #if VMA_VULKAN_VERSION < 1001000
    +
    16147  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16148  {
    +
    16149  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros.");
    +
    16150  }
    +
    16151 #endif
    +
    16152 #if !(VMA_MEMORY_PRIORITY)
    +
    16153  if(m_UseExtMemoryPriority)
    +
    16154  {
    +
    16155  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
    +
    16156  }
    +
    16157 #endif
    +
    16158 
    +
    16159  memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
    +
    16160  memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
    +
    16161  memset(&m_MemProps, 0, sizeof(m_MemProps));
    +
    16162 
    +
    16163  memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
    +
    16164  memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions));
    +
    16165 
    +
    16166 #if VMA_EXTERNAL_MEMORY
    +
    16167  memset(&m_TypeExternalMemoryHandleTypes, 0, sizeof(m_TypeExternalMemoryHandleTypes));
    +
    16168 #endif // #if VMA_EXTERNAL_MEMORY
    +
    16169 
    +
    16170  if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
    +
    16171  {
    +
    16172  m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData;
    +
    16173  m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
    +
    16174  m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
    +
    16175  }
    16176 
    -
    16177 #if VMA_EXTERNAL_MEMORY
    -
    16178  if(pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL)
    -
    16179  {
    -
    16180  memcpy(m_TypeExternalMemoryHandleTypes, pCreateInfo->pTypeExternalMemoryHandleTypes,
    -
    16181  sizeof(VkExternalMemoryHandleTypeFlagsKHR) * GetMemoryTypeCount());
    -
    16182  }
    -
    16183 #endif // #if VMA_EXTERNAL_MEMORY
    -
    16184 
    -
    16185  if(pCreateInfo->pHeapSizeLimit != VMA_NULL)
    -
    16186  {
    -
    16187  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
    -
    16188  {
    -
    16189  const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex];
    -
    16190  if(limit != VK_WHOLE_SIZE)
    -
    16191  {
    -
    16192  m_HeapSizeLimitMask |= 1u << heapIndex;
    -
    16193  if(limit < m_MemProps.memoryHeaps[heapIndex].size)
    -
    16194  {
    -
    16195  m_MemProps.memoryHeaps[heapIndex].size = limit;
    -
    16196  }
    -
    16197  }
    -
    16198  }
    -
    16199  }
    -
    16200 
    -
    16201  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    16202  {
    -
    16203  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex);
    -
    16204 
    -
    16205  m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)(
    -
    16206  this,
    -
    16207  VK_NULL_HANDLE, // hParentPool
    -
    16208  memTypeIndex,
    -
    16209  preferredBlockSize,
    -
    16210  0,
    -
    16211  SIZE_MAX,
    -
    16212  GetBufferImageGranularity(),
    -
    16213  pCreateInfo->frameInUseCount,
    -
    16214  false, // explicitBlockSize
    -
    16215  false, // linearAlgorithm
    -
    16216  0.5f, // priority (0.5 is the default per Vulkan spec)
    -
    16217  GetMemoryTypeMinAlignment(memTypeIndex), // minAllocationAlignment
    -
    16218  VMA_NULL); // // pMemoryAllocateNext
    -
    16219  // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here,
    -
    16220  // becase minBlockCount is 0.
    -
    16221  }
    -
    16222 }
    -
    16223 
    -
    16224 VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo)
    -
    16225 {
    -
    16226  VkResult res = VK_SUCCESS;
    -
    16227 
    -
    16228  if(pCreateInfo->pRecordSettings != VMA_NULL &&
    -
    16229  !VmaStrIsEmpty(pCreateInfo->pRecordSettings->pFilePath))
    -
    16230  {
    -
    16231 #if VMA_RECORDING_ENABLED
    -
    16232  m_pRecorder = vma_new(this, VmaRecorder)();
    -
    16233  res = m_pRecorder->Init(*pCreateInfo->pRecordSettings, m_UseMutex);
    -
    16234  if(res != VK_SUCCESS)
    -
    16235  {
    -
    16236  return res;
    -
    16237  }
    -
    16238  m_pRecorder->WriteConfiguration(
    -
    16239  m_PhysicalDeviceProperties,
    -
    16240  m_MemProps,
    -
    16241  m_VulkanApiVersion,
    -
    16242  m_UseKhrDedicatedAllocation,
    -
    16243  m_UseKhrBindMemory2,
    -
    16244  m_UseExtMemoryBudget,
    -
    16245  m_UseAmdDeviceCoherentMemory);
    -
    16246  m_pRecorder->RecordCreateAllocator(GetCurrentFrameIndex());
    -
    16247 #else
    -
    16248  VMA_ASSERT(0 && "VmaAllocatorCreateInfo::pRecordSettings used, but not supported due to VMA_RECORDING_ENABLED not defined to 1.");
    -
    16249  return VK_ERROR_FEATURE_NOT_PRESENT;
    -
    16250 #endif
    -
    16251  }
    -
    16252 
    -
    16253 #if VMA_MEMORY_BUDGET
    -
    16254  if(m_UseExtMemoryBudget)
    -
    16255  {
    -
    16256  UpdateVulkanBudget();
    -
    16257  }
    -
    16258 #endif // #if VMA_MEMORY_BUDGET
    -
    16259 
    -
    16260  return res;
    -
    16261 }
    -
    16262 
    -
    16263 VmaAllocator_T::~VmaAllocator_T()
    -
    16264 {
    -
    16265 #if VMA_RECORDING_ENABLED
    -
    16266  if(m_pRecorder != VMA_NULL)
    -
    16267  {
    -
    16268  m_pRecorder->RecordDestroyAllocator(GetCurrentFrameIndex());
    -
    16269  vma_delete(this, m_pRecorder);
    -
    16270  }
    -
    16271 #endif
    -
    16272 
    -
    16273  VMA_ASSERT(m_Pools.IsEmpty());
    +
    16177  ImportVulkanFunctions(pCreateInfo->pVulkanFunctions);
    +
    16178 
    +
    16179  (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties);
    +
    16180  (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
    +
    16181 
    +
    16182  VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT));
    +
    16183  VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY));
    +
    16184  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity));
    +
    16185  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize));
    +
    16186 
    +
    16187  m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
    +
    16188  pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
    +
    16189 
    +
    16190  m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits();
    +
    16191 
    +
    16192 #if VMA_EXTERNAL_MEMORY
    +
    16193  if(pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL)
    +
    16194  {
    +
    16195  memcpy(m_TypeExternalMemoryHandleTypes, pCreateInfo->pTypeExternalMemoryHandleTypes,
    +
    16196  sizeof(VkExternalMemoryHandleTypeFlagsKHR) * GetMemoryTypeCount());
    +
    16197  }
    +
    16198 #endif // #if VMA_EXTERNAL_MEMORY
    +
    16199 
    +
    16200  if(pCreateInfo->pHeapSizeLimit != VMA_NULL)
    +
    16201  {
    +
    16202  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
    +
    16203  {
    +
    16204  const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex];
    +
    16205  if(limit != VK_WHOLE_SIZE)
    +
    16206  {
    +
    16207  m_HeapSizeLimitMask |= 1u << heapIndex;
    +
    16208  if(limit < m_MemProps.memoryHeaps[heapIndex].size)
    +
    16209  {
    +
    16210  m_MemProps.memoryHeaps[heapIndex].size = limit;
    +
    16211  }
    +
    16212  }
    +
    16213  }
    +
    16214  }
    +
    16215 
    +
    16216  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    16217  {
    +
    16218  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex);
    +
    16219 
    +
    16220  m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)(
    +
    16221  this,
    +
    16222  VK_NULL_HANDLE, // hParentPool
    +
    16223  memTypeIndex,
    +
    16224  preferredBlockSize,
    +
    16225  0,
    +
    16226  SIZE_MAX,
    +
    16227  GetBufferImageGranularity(),
    +
    16228  pCreateInfo->frameInUseCount,
    +
    16229  false, // explicitBlockSize
    +
    16230  false, // linearAlgorithm
    +
    16231  0.5f, // priority (0.5 is the default per Vulkan spec)
    +
    16232  GetMemoryTypeMinAlignment(memTypeIndex), // minAllocationAlignment
    +
    16233  VMA_NULL); // // pMemoryAllocateNext
    +
    16234  // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here,
    +
    16235  // becase minBlockCount is 0.
    +
    16236  }
    +
    16237 }
    +
    16238 
    +
    16239 VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo)
    +
    16240 {
    +
    16241  VkResult res = VK_SUCCESS;
    +
    16242 
    +
    16243  if(pCreateInfo->pRecordSettings != VMA_NULL &&
    +
    16244  !VmaStrIsEmpty(pCreateInfo->pRecordSettings->pFilePath))
    +
    16245  {
    +
    16246 #if VMA_RECORDING_ENABLED
    +
    16247  m_pRecorder = vma_new(this, VmaRecorder)();
    +
    16248  res = m_pRecorder->Init(*pCreateInfo->pRecordSettings, m_UseMutex);
    +
    16249  if(res != VK_SUCCESS)
    +
    16250  {
    +
    16251  return res;
    +
    16252  }
    +
    16253  m_pRecorder->WriteConfiguration(
    +
    16254  m_PhysicalDeviceProperties,
    +
    16255  m_MemProps,
    +
    16256  m_VulkanApiVersion,
    +
    16257  m_UseKhrDedicatedAllocation,
    +
    16258  m_UseKhrBindMemory2,
    +
    16259  m_UseExtMemoryBudget,
    +
    16260  m_UseAmdDeviceCoherentMemory);
    +
    16261  m_pRecorder->RecordCreateAllocator(GetCurrentFrameIndex());
    +
    16262 #else
    +
    16263  VMA_ASSERT(0 && "VmaAllocatorCreateInfo::pRecordSettings used, but not supported due to VMA_RECORDING_ENABLED not defined to 1.");
    +
    16264  return VK_ERROR_FEATURE_NOT_PRESENT;
    +
    16265 #endif
    +
    16266  }
    +
    16267 
    +
    16268 #if VMA_MEMORY_BUDGET
    +
    16269  if(m_UseExtMemoryBudget)
    +
    16270  {
    +
    16271  UpdateVulkanBudget();
    +
    16272  }
    +
    16273 #endif // #if VMA_MEMORY_BUDGET
    16274 
    -
    16275  for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
    -
    16276  {
    -
    16277  if(!m_DedicatedAllocations[memTypeIndex].IsEmpty())
    -
    16278  {
    -
    16279  VMA_ASSERT(0 && "Unfreed dedicated allocations found.");
    -
    16280  }
    -
    16281 
    -
    16282  vma_delete(this, m_pBlockVectors[memTypeIndex]);
    -
    16283  }
    -
    16284 }
    -
    16285 
    -
    16286 void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions)
    -
    16287 {
    -
    16288 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    -
    16289  ImportVulkanFunctions_Static();
    -
    16290 #endif
    -
    16291 
    -
    16292  if(pVulkanFunctions != VMA_NULL)
    -
    16293  {
    -
    16294  ImportVulkanFunctions_Custom(pVulkanFunctions);
    -
    16295  }
    +
    16275  return res;
    +
    16276 }
    +
    16277 
    +
    16278 VmaAllocator_T::~VmaAllocator_T()
    +
    16279 {
    +
    16280 #if VMA_RECORDING_ENABLED
    +
    16281  if(m_pRecorder != VMA_NULL)
    +
    16282  {
    +
    16283  m_pRecorder->RecordDestroyAllocator(GetCurrentFrameIndex());
    +
    16284  vma_delete(this, m_pRecorder);
    +
    16285  }
    +
    16286 #endif
    +
    16287 
    +
    16288  VMA_ASSERT(m_Pools.IsEmpty());
    +
    16289 
    +
    16290  for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
    +
    16291  {
    +
    16292  if(!m_DedicatedAllocations[memTypeIndex].IsEmpty())
    +
    16293  {
    +
    16294  VMA_ASSERT(0 && "Unfreed dedicated allocations found.");
    +
    16295  }
    16296 
    -
    16297 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    -
    16298  ImportVulkanFunctions_Dynamic();
    -
    16299 #endif
    +
    16297  vma_delete(this, m_pBlockVectors[memTypeIndex]);
    +
    16298  }
    +
    16299 }
    16300 
    -
    16301  ValidateVulkanFunctions();
    -
    16302 }
    -
    16303 
    -
    16304 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    -
    16305 
    -
    16306 void VmaAllocator_T::ImportVulkanFunctions_Static()
    -
    16307 {
    -
    16308  // Vulkan 1.0
    -
    16309  m_VulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetPhysicalDeviceProperties;
    -
    16310  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetPhysicalDeviceMemoryProperties;
    -
    16311  m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory;
    -
    16312  m_VulkanFunctions.vkFreeMemory = (PFN_vkFreeMemory)vkFreeMemory;
    -
    16313  m_VulkanFunctions.vkMapMemory = (PFN_vkMapMemory)vkMapMemory;
    -
    16314  m_VulkanFunctions.vkUnmapMemory = (PFN_vkUnmapMemory)vkUnmapMemory;
    -
    16315  m_VulkanFunctions.vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)vkFlushMappedMemoryRanges;
    -
    16316  m_VulkanFunctions.vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)vkInvalidateMappedMemoryRanges;
    -
    16317  m_VulkanFunctions.vkBindBufferMemory = (PFN_vkBindBufferMemory)vkBindBufferMemory;
    -
    16318  m_VulkanFunctions.vkBindImageMemory = (PFN_vkBindImageMemory)vkBindImageMemory;
    -
    16319  m_VulkanFunctions.vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)vkGetBufferMemoryRequirements;
    -
    16320  m_VulkanFunctions.vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vkGetImageMemoryRequirements;
    -
    16321  m_VulkanFunctions.vkCreateBuffer = (PFN_vkCreateBuffer)vkCreateBuffer;
    -
    16322  m_VulkanFunctions.vkDestroyBuffer = (PFN_vkDestroyBuffer)vkDestroyBuffer;
    -
    16323  m_VulkanFunctions.vkCreateImage = (PFN_vkCreateImage)vkCreateImage;
    -
    16324  m_VulkanFunctions.vkDestroyImage = (PFN_vkDestroyImage)vkDestroyImage;
    -
    16325  m_VulkanFunctions.vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)vkCmdCopyBuffer;
    -
    16326 
    -
    16327  // Vulkan 1.1
    -
    16328 #if VMA_VULKAN_VERSION >= 1001000
    -
    16329  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    -
    16330  {
    -
    16331  m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2;
    -
    16332  m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2;
    -
    16333  m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2;
    -
    16334  m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2;
    -
    16335  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2;
    -
    16336  }
    -
    16337 #endif
    -
    16338 }
    -
    16339 
    -
    16340 #endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    +
    16301 void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions)
    +
    16302 {
    +
    16303 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    +
    16304  ImportVulkanFunctions_Static();
    +
    16305 #endif
    +
    16306 
    +
    16307  if(pVulkanFunctions != VMA_NULL)
    +
    16308  {
    +
    16309  ImportVulkanFunctions_Custom(pVulkanFunctions);
    +
    16310  }
    +
    16311 
    +
    16312 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    +
    16313  ImportVulkanFunctions_Dynamic();
    +
    16314 #endif
    +
    16315 
    +
    16316  ValidateVulkanFunctions();
    +
    16317 }
    +
    16318 
    +
    16319 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    +
    16320 
    +
    16321 void VmaAllocator_T::ImportVulkanFunctions_Static()
    +
    16322 {
    +
    16323  // Vulkan 1.0
    +
    16324  m_VulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetPhysicalDeviceProperties;
    +
    16325  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetPhysicalDeviceMemoryProperties;
    +
    16326  m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory;
    +
    16327  m_VulkanFunctions.vkFreeMemory = (PFN_vkFreeMemory)vkFreeMemory;
    +
    16328  m_VulkanFunctions.vkMapMemory = (PFN_vkMapMemory)vkMapMemory;
    +
    16329  m_VulkanFunctions.vkUnmapMemory = (PFN_vkUnmapMemory)vkUnmapMemory;
    +
    16330  m_VulkanFunctions.vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)vkFlushMappedMemoryRanges;
    +
    16331  m_VulkanFunctions.vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)vkInvalidateMappedMemoryRanges;
    +
    16332  m_VulkanFunctions.vkBindBufferMemory = (PFN_vkBindBufferMemory)vkBindBufferMemory;
    +
    16333  m_VulkanFunctions.vkBindImageMemory = (PFN_vkBindImageMemory)vkBindImageMemory;
    +
    16334  m_VulkanFunctions.vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)vkGetBufferMemoryRequirements;
    +
    16335  m_VulkanFunctions.vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vkGetImageMemoryRequirements;
    +
    16336  m_VulkanFunctions.vkCreateBuffer = (PFN_vkCreateBuffer)vkCreateBuffer;
    +
    16337  m_VulkanFunctions.vkDestroyBuffer = (PFN_vkDestroyBuffer)vkDestroyBuffer;
    +
    16338  m_VulkanFunctions.vkCreateImage = (PFN_vkCreateImage)vkCreateImage;
    +
    16339  m_VulkanFunctions.vkDestroyImage = (PFN_vkDestroyImage)vkDestroyImage;
    +
    16340  m_VulkanFunctions.vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)vkCmdCopyBuffer;
    16341 
    -
    16342 void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions)
    -
    16343 {
    -
    16344  VMA_ASSERT(pVulkanFunctions != VMA_NULL);
    -
    16345 
    -
    16346 #define VMA_COPY_IF_NOT_NULL(funcName) \
    -
    16347  if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName;
    -
    16348 
    -
    16349  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties);
    -
    16350  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties);
    -
    16351  VMA_COPY_IF_NOT_NULL(vkAllocateMemory);
    -
    16352  VMA_COPY_IF_NOT_NULL(vkFreeMemory);
    -
    16353  VMA_COPY_IF_NOT_NULL(vkMapMemory);
    -
    16354  VMA_COPY_IF_NOT_NULL(vkUnmapMemory);
    -
    16355  VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges);
    -
    16356  VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges);
    -
    16357  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory);
    -
    16358  VMA_COPY_IF_NOT_NULL(vkBindImageMemory);
    -
    16359  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements);
    -
    16360  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements);
    -
    16361  VMA_COPY_IF_NOT_NULL(vkCreateBuffer);
    -
    16362  VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
    -
    16363  VMA_COPY_IF_NOT_NULL(vkCreateImage);
    -
    16364  VMA_COPY_IF_NOT_NULL(vkDestroyImage);
    -
    16365  VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer);
    -
    16366 
    -
    16367 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16368  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
    -
    16369  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
    -
    16370 #endif
    -
    16371 
    -
    16372 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
    -
    16373  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR);
    -
    16374  VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR);
    -
    16375 #endif
    -
    16376 
    -
    16377 #if VMA_MEMORY_BUDGET
    -
    16378  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR);
    -
    16379 #endif
    -
    16380 
    -
    16381 #undef VMA_COPY_IF_NOT_NULL
    -
    16382 }
    -
    16383 
    -
    16384 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    -
    16385 
    -
    16386 void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
    -
    16387 {
    -
    16388 #define VMA_FETCH_INSTANCE_FUNC(memberName, functionPointerType, functionNameString) \
    -
    16389  if(m_VulkanFunctions.memberName == VMA_NULL) \
    -
    16390  m_VulkanFunctions.memberName = \
    -
    16391  (functionPointerType)vkGetInstanceProcAddr(m_hInstance, functionNameString);
    -
    16392 #define VMA_FETCH_DEVICE_FUNC(memberName, functionPointerType, functionNameString) \
    -
    16393  if(m_VulkanFunctions.memberName == VMA_NULL) \
    -
    16394  m_VulkanFunctions.memberName = \
    -
    16395  (functionPointerType)vkGetDeviceProcAddr(m_hDevice, functionNameString);
    -
    16396 
    -
    16397  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
    -
    16398  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties, PFN_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
    -
    16399  VMA_FETCH_DEVICE_FUNC(vkAllocateMemory, PFN_vkAllocateMemory, "vkAllocateMemory");
    -
    16400  VMA_FETCH_DEVICE_FUNC(vkFreeMemory, PFN_vkFreeMemory, "vkFreeMemory");
    -
    16401  VMA_FETCH_DEVICE_FUNC(vkMapMemory, PFN_vkMapMemory, "vkMapMemory");
    -
    16402  VMA_FETCH_DEVICE_FUNC(vkUnmapMemory, PFN_vkUnmapMemory, "vkUnmapMemory");
    -
    16403  VMA_FETCH_DEVICE_FUNC(vkFlushMappedMemoryRanges, PFN_vkFlushMappedMemoryRanges, "vkFlushMappedMemoryRanges");
    -
    16404  VMA_FETCH_DEVICE_FUNC(vkInvalidateMappedMemoryRanges, PFN_vkInvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges");
    -
    16405  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory, PFN_vkBindBufferMemory, "vkBindBufferMemory");
    -
    16406  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory, PFN_vkBindImageMemory, "vkBindImageMemory");
    -
    16407  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements, PFN_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements");
    -
    16408  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements, PFN_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements");
    -
    16409  VMA_FETCH_DEVICE_FUNC(vkCreateBuffer, PFN_vkCreateBuffer, "vkCreateBuffer");
    -
    16410  VMA_FETCH_DEVICE_FUNC(vkDestroyBuffer, PFN_vkDestroyBuffer, "vkDestroyBuffer");
    -
    16411  VMA_FETCH_DEVICE_FUNC(vkCreateImage, PFN_vkCreateImage, "vkCreateImage");
    -
    16412  VMA_FETCH_DEVICE_FUNC(vkDestroyImage, PFN_vkDestroyImage, "vkDestroyImage");
    -
    16413  VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer");
    -
    16414 
    -
    16415 #if VMA_VULKAN_VERSION >= 1001000
    -
    16416  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    -
    16417  {
    -
    16418  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2");
    -
    16419  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2");
    -
    16420  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2");
    -
    16421  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2");
    -
    16422  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
    -
    16423  }
    -
    16424 #endif
    -
    16425 
    -
    16426 #if VMA_DEDICATED_ALLOCATION
    -
    16427  if(m_UseKhrDedicatedAllocation)
    -
    16428  {
    -
    16429  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR");
    -
    16430  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR");
    -
    16431  }
    -
    16432 #endif
    -
    16433 
    -
    16434 #if VMA_BIND_MEMORY2
    -
    16435  if(m_UseKhrBindMemory2)
    -
    16436  {
    -
    16437  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR");
    -
    16438  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR");
    -
    16439  }
    -
    16440 #endif // #if VMA_BIND_MEMORY2
    -
    16441 
    -
    16442 #if VMA_MEMORY_BUDGET
    -
    16443  if(m_UseExtMemoryBudget)
    -
    16444  {
    -
    16445  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR");
    +
    16342  // Vulkan 1.1
    +
    16343 #if VMA_VULKAN_VERSION >= 1001000
    +
    16344  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16345  {
    +
    16346  m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2;
    +
    16347  m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2;
    +
    16348  m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2;
    +
    16349  m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2;
    +
    16350  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2;
    +
    16351  }
    +
    16352 #endif
    +
    16353 }
    +
    16354 
    +
    16355 #endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1
    +
    16356 
    +
    16357 void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions)
    +
    16358 {
    +
    16359  VMA_ASSERT(pVulkanFunctions != VMA_NULL);
    +
    16360 
    +
    16361 #define VMA_COPY_IF_NOT_NULL(funcName) \
    +
    16362  if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName;
    +
    16363 
    +
    16364  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties);
    +
    16365  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties);
    +
    16366  VMA_COPY_IF_NOT_NULL(vkAllocateMemory);
    +
    16367  VMA_COPY_IF_NOT_NULL(vkFreeMemory);
    +
    16368  VMA_COPY_IF_NOT_NULL(vkMapMemory);
    +
    16369  VMA_COPY_IF_NOT_NULL(vkUnmapMemory);
    +
    16370  VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges);
    +
    16371  VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges);
    +
    16372  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory);
    +
    16373  VMA_COPY_IF_NOT_NULL(vkBindImageMemory);
    +
    16374  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements);
    +
    16375  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements);
    +
    16376  VMA_COPY_IF_NOT_NULL(vkCreateBuffer);
    +
    16377  VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
    +
    16378  VMA_COPY_IF_NOT_NULL(vkCreateImage);
    +
    16379  VMA_COPY_IF_NOT_NULL(vkDestroyImage);
    +
    16380  VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer);
    +
    16381 
    +
    16382 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16383  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
    +
    16384  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
    +
    16385 #endif
    +
    16386 
    +
    16387 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
    +
    16388  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR);
    +
    16389  VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR);
    +
    16390 #endif
    +
    16391 
    +
    16392 #if VMA_MEMORY_BUDGET
    +
    16393  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR);
    +
    16394 #endif
    +
    16395 
    +
    16396 #undef VMA_COPY_IF_NOT_NULL
    +
    16397 }
    +
    16398 
    +
    16399 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    +
    16400 
    +
    16401 void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
    +
    16402 {
    +
    16403 #define VMA_FETCH_INSTANCE_FUNC(memberName, functionPointerType, functionNameString) \
    +
    16404  if(m_VulkanFunctions.memberName == VMA_NULL) \
    +
    16405  m_VulkanFunctions.memberName = \
    +
    16406  (functionPointerType)vkGetInstanceProcAddr(m_hInstance, functionNameString);
    +
    16407 #define VMA_FETCH_DEVICE_FUNC(memberName, functionPointerType, functionNameString) \
    +
    16408  if(m_VulkanFunctions.memberName == VMA_NULL) \
    +
    16409  m_VulkanFunctions.memberName = \
    +
    16410  (functionPointerType)vkGetDeviceProcAddr(m_hDevice, functionNameString);
    +
    16411 
    +
    16412  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
    +
    16413  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties, PFN_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
    +
    16414  VMA_FETCH_DEVICE_FUNC(vkAllocateMemory, PFN_vkAllocateMemory, "vkAllocateMemory");
    +
    16415  VMA_FETCH_DEVICE_FUNC(vkFreeMemory, PFN_vkFreeMemory, "vkFreeMemory");
    +
    16416  VMA_FETCH_DEVICE_FUNC(vkMapMemory, PFN_vkMapMemory, "vkMapMemory");
    +
    16417  VMA_FETCH_DEVICE_FUNC(vkUnmapMemory, PFN_vkUnmapMemory, "vkUnmapMemory");
    +
    16418  VMA_FETCH_DEVICE_FUNC(vkFlushMappedMemoryRanges, PFN_vkFlushMappedMemoryRanges, "vkFlushMappedMemoryRanges");
    +
    16419  VMA_FETCH_DEVICE_FUNC(vkInvalidateMappedMemoryRanges, PFN_vkInvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges");
    +
    16420  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory, PFN_vkBindBufferMemory, "vkBindBufferMemory");
    +
    16421  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory, PFN_vkBindImageMemory, "vkBindImageMemory");
    +
    16422  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements, PFN_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements");
    +
    16423  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements, PFN_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements");
    +
    16424  VMA_FETCH_DEVICE_FUNC(vkCreateBuffer, PFN_vkCreateBuffer, "vkCreateBuffer");
    +
    16425  VMA_FETCH_DEVICE_FUNC(vkDestroyBuffer, PFN_vkDestroyBuffer, "vkDestroyBuffer");
    +
    16426  VMA_FETCH_DEVICE_FUNC(vkCreateImage, PFN_vkCreateImage, "vkCreateImage");
    +
    16427  VMA_FETCH_DEVICE_FUNC(vkDestroyImage, PFN_vkDestroyImage, "vkDestroyImage");
    +
    16428  VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer");
    +
    16429 
    +
    16430 #if VMA_VULKAN_VERSION >= 1001000
    +
    16431  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16432  {
    +
    16433  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2");
    +
    16434  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2");
    +
    16435  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2");
    +
    16436  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2");
    +
    16437  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
    +
    16438  }
    +
    16439 #endif
    +
    16440 
    +
    16441 #if VMA_DEDICATED_ALLOCATION
    +
    16442  if(m_UseKhrDedicatedAllocation)
    +
    16443  {
    +
    16444  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR");
    +
    16445  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR");
    16446  }
    -
    16447 #endif // #if VMA_MEMORY_BUDGET
    +
    16447 #endif
    16448 
    -
    16449 #undef VMA_FETCH_DEVICE_FUNC
    -
    16450 #undef VMA_FETCH_INSTANCE_FUNC
    -
    16451 }
    -
    16452 
    -
    16453 #endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    -
    16454 
    -
    16455 void VmaAllocator_T::ValidateVulkanFunctions()
    -
    16456 {
    -
    16457  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL);
    -
    16458  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL);
    -
    16459  VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL);
    -
    16460  VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL);
    -
    16461  VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL);
    -
    16462  VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL);
    -
    16463  VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL);
    -
    16464  VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL);
    -
    16465  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL);
    -
    16466  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL);
    -
    16467  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL);
    -
    16468  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL);
    -
    16469  VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL);
    -
    16470  VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
    -
    16471  VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
    -
    16472  VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
    -
    16473  VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL);
    -
    16474 
    -
    16475 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16476  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation)
    -
    16477  {
    -
    16478  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL);
    -
    16479  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL);
    -
    16480  }
    -
    16481 #endif
    -
    16482 
    -
    16483 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
    -
    16484  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2)
    -
    16485  {
    -
    16486  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL);
    -
    16487  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL);
    -
    16488  }
    -
    16489 #endif
    -
    16490 
    -
    16491 #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000
    -
    16492  if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    -
    16493  {
    -
    16494  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
    +
    16449 #if VMA_BIND_MEMORY2
    +
    16450  if(m_UseKhrBindMemory2)
    +
    16451  {
    +
    16452  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR");
    +
    16453  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR");
    +
    16454  }
    +
    16455 #endif // #if VMA_BIND_MEMORY2
    +
    16456 
    +
    16457 #if VMA_MEMORY_BUDGET
    +
    16458  if(m_UseExtMemoryBudget)
    +
    16459  {
    +
    16460  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR");
    +
    16461  }
    +
    16462 #endif // #if VMA_MEMORY_BUDGET
    +
    16463 
    +
    16464 #undef VMA_FETCH_DEVICE_FUNC
    +
    16465 #undef VMA_FETCH_INSTANCE_FUNC
    +
    16466 }
    +
    16467 
    +
    16468 #endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
    +
    16469 
    +
    16470 void VmaAllocator_T::ValidateVulkanFunctions()
    +
    16471 {
    +
    16472  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL);
    +
    16473  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL);
    +
    16474  VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL);
    +
    16475  VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL);
    +
    16476  VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL);
    +
    16477  VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL);
    +
    16478  VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL);
    +
    16479  VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL);
    +
    16480  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL);
    +
    16481  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL);
    +
    16482  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL);
    +
    16483  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL);
    +
    16484  VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL);
    +
    16485  VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
    +
    16486  VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
    +
    16487  VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
    +
    16488  VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL);
    +
    16489 
    +
    16490 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16491  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation)
    +
    16492  {
    +
    16493  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL);
    +
    16494  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL);
    16495  }
    16496 #endif
    -
    16497 }
    -
    16498 
    -
    16499 VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
    -
    16500 {
    -
    16501  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
    -
    16502  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
    -
    16503  const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE;
    -
    16504  return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32);
    -
    16505 }
    -
    16506 
    -
    16507 VkResult VmaAllocator_T::AllocateMemoryOfType(
    -
    16508  VkDeviceSize size,
    -
    16509  VkDeviceSize alignment,
    -
    16510  bool dedicatedAllocation,
    -
    16511  VkBuffer dedicatedBuffer,
    -
    16512  VkBufferUsageFlags dedicatedBufferUsage,
    -
    16513  VkImage dedicatedImage,
    -
    16514  const VmaAllocationCreateInfo& createInfo,
    -
    16515  uint32_t memTypeIndex,
    -
    16516  VmaSuballocationType suballocType,
    -
    16517  size_t allocationCount,
    -
    16518  VmaAllocation* pAllocations)
    -
    16519 {
    -
    16520  VMA_ASSERT(pAllocations != VMA_NULL);
    -
    16521  VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size);
    -
    16522 
    -
    16523  VmaAllocationCreateInfo finalCreateInfo = createInfo;
    -
    16524 
    -
    16525  // If memory type is not HOST_VISIBLE, disable MAPPED.
    -
    16526  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
    -
    16527  (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    -
    16528  {
    -
    16529  finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
    -
    16530  }
    -
    16531  // If memory is lazily allocated, it should be always dedicated.
    -
    16532  if(finalCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED)
    -
    16533  {
    -
    16534  finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
    -
    16535  }
    -
    16536 
    -
    16537  VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex];
    -
    16538  VMA_ASSERT(blockVector);
    +
    16497 
    +
    16498 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
    +
    16499  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2)
    +
    16500  {
    +
    16501  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL);
    +
    16502  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL);
    +
    16503  }
    +
    16504 #endif
    +
    16505 
    +
    16506 #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000
    +
    16507  if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16508  {
    +
    16509  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
    +
    16510  }
    +
    16511 #endif
    +
    16512 }
    +
    16513 
    +
    16514 VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
    +
    16515 {
    +
    16516  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
    +
    16517  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
    +
    16518  const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE;
    +
    16519  return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32);
    +
    16520 }
    +
    16521 
    +
    16522 VkResult VmaAllocator_T::AllocateMemoryOfType(
    +
    16523  VkDeviceSize size,
    +
    16524  VkDeviceSize alignment,
    +
    16525  bool dedicatedAllocation,
    +
    16526  VkBuffer dedicatedBuffer,
    +
    16527  VkBufferUsageFlags dedicatedBufferUsage,
    +
    16528  VkImage dedicatedImage,
    +
    16529  const VmaAllocationCreateInfo& createInfo,
    +
    16530  uint32_t memTypeIndex,
    +
    16531  VmaSuballocationType suballocType,
    +
    16532  size_t allocationCount,
    +
    16533  VmaAllocation* pAllocations)
    +
    16534 {
    +
    16535  VMA_ASSERT(pAllocations != VMA_NULL);
    +
    16536  VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size);
    +
    16537 
    +
    16538  VmaAllocationCreateInfo finalCreateInfo = createInfo;
    16539 
    -
    16540  const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
    -
    16541  bool preferDedicatedMemory =
    -
    16542  VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
    -
    16543  dedicatedAllocation ||
    -
    16544  // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
    -
    16545  size > preferredBlockSize / 2;
    -
    16546 
    -
    16547  if(preferDedicatedMemory &&
    -
    16548  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
    -
    16549  finalCreateInfo.pool == VK_NULL_HANDLE)
    -
    16550  {
    -
    16551  finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
    -
    16552  }
    -
    16553 
    -
    16554  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
    -
    16555  {
    -
    16556  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    -
    16557  {
    -
    16558  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16559  }
    -
    16560  else
    -
    16561  {
    -
    16562  return AllocateDedicatedMemory(
    -
    16563  size,
    -
    16564  suballocType,
    -
    16565  memTypeIndex,
    -
    16566  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
    -
    16567  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
    -
    16568  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
    -
    16569  finalCreateInfo.pUserData,
    -
    16570  finalCreateInfo.priority,
    -
    16571  dedicatedBuffer,
    -
    16572  dedicatedBufferUsage,
    -
    16573  dedicatedImage,
    -
    16574  allocationCount,
    -
    16575  pAllocations);
    -
    16576  }
    -
    16577  }
    -
    16578  else
    -
    16579  {
    -
    16580  VkResult res = blockVector->Allocate(
    -
    16581  m_CurrentFrameIndex.load(),
    -
    16582  size,
    -
    16583  alignment,
    -
    16584  finalCreateInfo,
    -
    16585  suballocType,
    -
    16586  allocationCount,
    -
    16587  pAllocations);
    -
    16588  if(res == VK_SUCCESS)
    -
    16589  {
    -
    16590  return res;
    +
    16540  // If memory type is not HOST_VISIBLE, disable MAPPED.
    +
    16541  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
    +
    16542  (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    +
    16543  {
    +
    16544  finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
    +
    16545  }
    +
    16546  // If memory is lazily allocated, it should be always dedicated.
    +
    16547  if(finalCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED)
    +
    16548  {
    +
    16549  finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
    +
    16550  }
    +
    16551 
    +
    16552  VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex];
    +
    16553  VMA_ASSERT(blockVector);
    +
    16554 
    +
    16555  const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
    +
    16556  bool preferDedicatedMemory =
    +
    16557  VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
    +
    16558  dedicatedAllocation ||
    +
    16559  // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
    +
    16560  size > preferredBlockSize / 2;
    +
    16561 
    +
    16562  if(preferDedicatedMemory &&
    +
    16563  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
    +
    16564  finalCreateInfo.pool == VK_NULL_HANDLE)
    +
    16565  {
    +
    16566  finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
    +
    16567  }
    +
    16568 
    +
    16569  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
    +
    16570  {
    +
    16571  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    +
    16572  {
    +
    16573  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16574  }
    +
    16575  else
    +
    16576  {
    +
    16577  return AllocateDedicatedMemory(
    +
    16578  size,
    +
    16579  suballocType,
    +
    16580  memTypeIndex,
    +
    16581  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
    +
    16582  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
    +
    16583  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
    +
    16584  finalCreateInfo.pUserData,
    +
    16585  finalCreateInfo.priority,
    +
    16586  dedicatedBuffer,
    +
    16587  dedicatedBufferUsage,
    +
    16588  dedicatedImage,
    +
    16589  allocationCount,
    +
    16590  pAllocations);
    16591  }
    -
    16592 
    -
    16593  // 5. Try dedicated memory.
    -
    16594  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    -
    16595  {
    -
    16596  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16597  }
    -
    16598 
    -
    16599  // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget,
    -
    16600  // which can quickly deplete maxMemoryAllocationCount: Don't try dedicated allocations when above
    -
    16601  // 3/4 of the maximum allocation count.
    -
    16602  if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4)
    -
    16603  {
    -
    16604  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16605  }
    -
    16606 
    -
    16607  res = AllocateDedicatedMemory(
    -
    16608  size,
    -
    16609  suballocType,
    -
    16610  memTypeIndex,
    -
    16611  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
    -
    16612  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
    -
    16613  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
    -
    16614  finalCreateInfo.pUserData,
    -
    16615  finalCreateInfo.priority,
    -
    16616  dedicatedBuffer,
    -
    16617  dedicatedBufferUsage,
    -
    16618  dedicatedImage,
    -
    16619  allocationCount,
    -
    16620  pAllocations);
    -
    16621  if(res == VK_SUCCESS)
    -
    16622  {
    -
    16623  // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
    -
    16624  VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
    -
    16625  return VK_SUCCESS;
    -
    16626  }
    -
    16627  else
    -
    16628  {
    -
    16629  // Everything failed: Return error code.
    -
    16630  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    -
    16631  return res;
    -
    16632  }
    -
    16633  }
    -
    16634 }
    -
    16635 
    -
    16636 VkResult VmaAllocator_T::AllocateDedicatedMemory(
    -
    16637  VkDeviceSize size,
    -
    16638  VmaSuballocationType suballocType,
    -
    16639  uint32_t memTypeIndex,
    -
    16640  bool withinBudget,
    -
    16641  bool map,
    -
    16642  bool isUserDataString,
    -
    16643  void* pUserData,
    -
    16644  float priority,
    -
    16645  VkBuffer dedicatedBuffer,
    -
    16646  VkBufferUsageFlags dedicatedBufferUsage,
    -
    16647  VkImage dedicatedImage,
    -
    16648  size_t allocationCount,
    -
    16649  VmaAllocation* pAllocations)
    -
    16650 {
    -
    16651  VMA_ASSERT(allocationCount > 0 && pAllocations);
    -
    16652 
    -
    16653  if(withinBudget)
    -
    16654  {
    -
    16655  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
    -
    16656  VmaBudget heapBudget = {};
    -
    16657  GetBudget(&heapBudget, heapIndex, 1);
    -
    16658  if(heapBudget.usage + size * allocationCount > heapBudget.budget)
    -
    16659  {
    -
    16660  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16661  }
    -
    16662  }
    -
    16663 
    -
    16664  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    -
    16665  allocInfo.memoryTypeIndex = memTypeIndex;
    -
    16666  allocInfo.allocationSize = size;
    +
    16592  }
    +
    16593  else
    +
    16594  {
    +
    16595  VkResult res = blockVector->Allocate(
    +
    16596  m_CurrentFrameIndex.load(),
    +
    16597  size,
    +
    16598  alignment,
    +
    16599  finalCreateInfo,
    +
    16600  suballocType,
    +
    16601  allocationCount,
    +
    16602  pAllocations);
    +
    16603  if(res == VK_SUCCESS)
    +
    16604  {
    +
    16605  return res;
    +
    16606  }
    +
    16607 
    +
    16608  // 5. Try dedicated memory.
    +
    16609  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    +
    16610  {
    +
    16611  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16612  }
    +
    16613 
    +
    16614  // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget,
    +
    16615  // which can quickly deplete maxMemoryAllocationCount: Don't try dedicated allocations when above
    +
    16616  // 3/4 of the maximum allocation count.
    +
    16617  if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4)
    +
    16618  {
    +
    16619  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16620  }
    +
    16621 
    +
    16622  res = AllocateDedicatedMemory(
    +
    16623  size,
    +
    16624  suballocType,
    +
    16625  memTypeIndex,
    +
    16626  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
    +
    16627  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
    +
    16628  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
    +
    16629  finalCreateInfo.pUserData,
    +
    16630  finalCreateInfo.priority,
    +
    16631  dedicatedBuffer,
    +
    16632  dedicatedBufferUsage,
    +
    16633  dedicatedImage,
    +
    16634  allocationCount,
    +
    16635  pAllocations);
    +
    16636  if(res == VK_SUCCESS)
    +
    16637  {
    +
    16638  // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
    +
    16639  VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
    +
    16640  return VK_SUCCESS;
    +
    16641  }
    +
    16642  else
    +
    16643  {
    +
    16644  // Everything failed: Return error code.
    +
    16645  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    +
    16646  return res;
    +
    16647  }
    +
    16648  }
    +
    16649 }
    +
    16650 
    +
    16651 VkResult VmaAllocator_T::AllocateDedicatedMemory(
    +
    16652  VkDeviceSize size,
    +
    16653  VmaSuballocationType suballocType,
    +
    16654  uint32_t memTypeIndex,
    +
    16655  bool withinBudget,
    +
    16656  bool map,
    +
    16657  bool isUserDataString,
    +
    16658  void* pUserData,
    +
    16659  float priority,
    +
    16660  VkBuffer dedicatedBuffer,
    +
    16661  VkBufferUsageFlags dedicatedBufferUsage,
    +
    16662  VkImage dedicatedImage,
    +
    16663  size_t allocationCount,
    +
    16664  VmaAllocation* pAllocations)
    +
    16665 {
    +
    16666  VMA_ASSERT(allocationCount > 0 && pAllocations);
    16667 
    -
    16668 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16669  VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
    -
    16670  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    -
    16671  {
    -
    16672  if(dedicatedBuffer != VK_NULL_HANDLE)
    -
    16673  {
    -
    16674  VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE);
    -
    16675  dedicatedAllocInfo.buffer = dedicatedBuffer;
    -
    16676  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
    -
    16677  }
    -
    16678  else if(dedicatedImage != VK_NULL_HANDLE)
    -
    16679  {
    -
    16680  dedicatedAllocInfo.image = dedicatedImage;
    -
    16681  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
    -
    16682  }
    -
    16683  }
    -
    16684 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16685 
    -
    16686 #if VMA_BUFFER_DEVICE_ADDRESS
    -
    16687  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
    -
    16688  if(m_UseKhrBufferDeviceAddress)
    -
    16689  {
    -
    16690  bool canContainBufferWithDeviceAddress = true;
    -
    16691  if(dedicatedBuffer != VK_NULL_HANDLE)
    -
    16692  {
    -
    16693  canContainBufferWithDeviceAddress = dedicatedBufferUsage == UINT32_MAX || // Usage flags unknown
    -
    16694  (dedicatedBufferUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0;
    -
    16695  }
    -
    16696  else if(dedicatedImage != VK_NULL_HANDLE)
    -
    16697  {
    -
    16698  canContainBufferWithDeviceAddress = false;
    -
    16699  }
    -
    16700  if(canContainBufferWithDeviceAddress)
    -
    16701  {
    -
    16702  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
    -
    16703  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
    -
    16704  }
    -
    16705  }
    -
    16706 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
    -
    16707 
    -
    16708 #if VMA_MEMORY_PRIORITY
    -
    16709  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
    -
    16710  if(m_UseExtMemoryPriority)
    -
    16711  {
    -
    16712  priorityInfo.priority = priority;
    -
    16713  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
    -
    16714  }
    -
    16715 #endif // #if VMA_MEMORY_PRIORITY
    -
    16716 
    -
    16717 #if VMA_EXTERNAL_MEMORY
    -
    16718  // Attach VkExportMemoryAllocateInfoKHR if necessary.
    -
    16719  VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR };
    -
    16720  exportMemoryAllocInfo.handleTypes = GetExternalMemoryHandleTypeFlags(memTypeIndex);
    -
    16721  if(exportMemoryAllocInfo.handleTypes != 0)
    -
    16722  {
    -
    16723  VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo);
    -
    16724  }
    -
    16725 #endif // #if VMA_EXTERNAL_MEMORY
    -
    16726 
    -
    16727  size_t allocIndex;
    -
    16728  VkResult res = VK_SUCCESS;
    -
    16729  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    -
    16730  {
    -
    16731  res = AllocateDedicatedMemoryPage(
    -
    16732  size,
    -
    16733  suballocType,
    -
    16734  memTypeIndex,
    -
    16735  allocInfo,
    -
    16736  map,
    -
    16737  isUserDataString,
    -
    16738  pUserData,
    -
    16739  pAllocations + allocIndex);
    -
    16740  if(res != VK_SUCCESS)
    -
    16741  {
    -
    16742  break;
    -
    16743  }
    -
    16744  }
    -
    16745 
    -
    16746  if(res == VK_SUCCESS)
    -
    16747  {
    -
    16748  // Register them in m_DedicatedAllocations.
    -
    16749  {
    -
    16750  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    -
    16751  DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
    -
    16752  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    -
    16753  {
    -
    16754  dedicatedAllocations.PushBack(pAllocations[allocIndex]);
    -
    16755  }
    -
    16756  }
    -
    16757 
    -
    16758  VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
    +
    16668  if(withinBudget)
    +
    16669  {
    +
    16670  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
    +
    16671  VmaBudget heapBudget = {};
    +
    16672  GetBudget(&heapBudget, heapIndex, 1);
    +
    16673  if(heapBudget.usage + size * allocationCount > heapBudget.budget)
    +
    16674  {
    +
    16675  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16676  }
    +
    16677  }
    +
    16678 
    +
    16679  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    +
    16680  allocInfo.memoryTypeIndex = memTypeIndex;
    +
    16681  allocInfo.allocationSize = size;
    +
    16682 
    +
    16683 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16684  VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
    +
    16685  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16686  {
    +
    16687  if(dedicatedBuffer != VK_NULL_HANDLE)
    +
    16688  {
    +
    16689  VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE);
    +
    16690  dedicatedAllocInfo.buffer = dedicatedBuffer;
    +
    16691  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
    +
    16692  }
    +
    16693  else if(dedicatedImage != VK_NULL_HANDLE)
    +
    16694  {
    +
    16695  dedicatedAllocInfo.image = dedicatedImage;
    +
    16696  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
    +
    16697  }
    +
    16698  }
    +
    16699 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16700 
    +
    16701 #if VMA_BUFFER_DEVICE_ADDRESS
    +
    16702  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
    +
    16703  if(m_UseKhrBufferDeviceAddress)
    +
    16704  {
    +
    16705  bool canContainBufferWithDeviceAddress = true;
    +
    16706  if(dedicatedBuffer != VK_NULL_HANDLE)
    +
    16707  {
    +
    16708  canContainBufferWithDeviceAddress = dedicatedBufferUsage == UINT32_MAX || // Usage flags unknown
    +
    16709  (dedicatedBufferUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0;
    +
    16710  }
    +
    16711  else if(dedicatedImage != VK_NULL_HANDLE)
    +
    16712  {
    +
    16713  canContainBufferWithDeviceAddress = false;
    +
    16714  }
    +
    16715  if(canContainBufferWithDeviceAddress)
    +
    16716  {
    +
    16717  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
    +
    16718  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
    +
    16719  }
    +
    16720  }
    +
    16721 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
    +
    16722 
    +
    16723 #if VMA_MEMORY_PRIORITY
    +
    16724  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
    +
    16725  if(m_UseExtMemoryPriority)
    +
    16726  {
    +
    16727  priorityInfo.priority = priority;
    +
    16728  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
    +
    16729  }
    +
    16730 #endif // #if VMA_MEMORY_PRIORITY
    +
    16731 
    +
    16732 #if VMA_EXTERNAL_MEMORY
    +
    16733  // Attach VkExportMemoryAllocateInfoKHR if necessary.
    +
    16734  VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR };
    +
    16735  exportMemoryAllocInfo.handleTypes = GetExternalMemoryHandleTypeFlags(memTypeIndex);
    +
    16736  if(exportMemoryAllocInfo.handleTypes != 0)
    +
    16737  {
    +
    16738  VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo);
    +
    16739  }
    +
    16740 #endif // #if VMA_EXTERNAL_MEMORY
    +
    16741 
    +
    16742  size_t allocIndex;
    +
    16743  VkResult res = VK_SUCCESS;
    +
    16744  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    +
    16745  {
    +
    16746  res = AllocateDedicatedMemoryPage(
    +
    16747  size,
    +
    16748  suballocType,
    +
    16749  memTypeIndex,
    +
    16750  allocInfo,
    +
    16751  map,
    +
    16752  isUserDataString,
    +
    16753  pUserData,
    +
    16754  pAllocations + allocIndex);
    +
    16755  if(res != VK_SUCCESS)
    +
    16756  {
    +
    16757  break;
    +
    16758  }
    16759  }
    -
    16760  else
    -
    16761  {
    -
    16762  // Free all already created allocations.
    -
    16763  while(allocIndex--)
    +
    16760 
    +
    16761  if(res == VK_SUCCESS)
    +
    16762  {
    +
    16763  // Register them in m_DedicatedAllocations.
    16764  {
    -
    16765  VmaAllocation currAlloc = pAllocations[allocIndex];
    -
    16766  VkDeviceMemory hMemory = currAlloc->GetMemory();
    -
    16767 
    -
    16768  /*
    -
    16769  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
    -
    16770  before vkFreeMemory.
    -
    16771 
    -
    16772  if(currAlloc->GetMappedData() != VMA_NULL)
    -
    16773  {
    -
    16774  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
    -
    16775  }
    -
    16776  */
    -
    16777 
    -
    16778  FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
    -
    16779  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize());
    -
    16780  currAlloc->SetUserData(this, VMA_NULL);
    -
    16781  m_AllocationObjectAllocator.Free(currAlloc);
    -
    16782  }
    -
    16783 
    -
    16784  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
    -
    16785  }
    -
    16786 
    -
    16787  return res;
    -
    16788 }
    -
    16789 
    -
    16790 VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
    -
    16791  VkDeviceSize size,
    -
    16792  VmaSuballocationType suballocType,
    -
    16793  uint32_t memTypeIndex,
    -
    16794  const VkMemoryAllocateInfo& allocInfo,
    -
    16795  bool map,
    -
    16796  bool isUserDataString,
    -
    16797  void* pUserData,
    -
    16798  VmaAllocation* pAllocation)
    -
    16799 {
    -
    16800  VkDeviceMemory hMemory = VK_NULL_HANDLE;
    -
    16801  VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
    -
    16802  if(res < 0)
    -
    16803  {
    -
    16804  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    -
    16805  return res;
    -
    16806  }
    -
    16807 
    -
    16808  void* pMappedData = VMA_NULL;
    -
    16809  if(map)
    -
    16810  {
    -
    16811  res = (*m_VulkanFunctions.vkMapMemory)(
    -
    16812  m_hDevice,
    -
    16813  hMemory,
    -
    16814  0,
    -
    16815  VK_WHOLE_SIZE,
    -
    16816  0,
    -
    16817  &pMappedData);
    -
    16818  if(res < 0)
    -
    16819  {
    -
    16820  VMA_DEBUG_LOG(" vkMapMemory FAILED");
    -
    16821  FreeVulkanMemory(memTypeIndex, size, hMemory);
    -
    16822  return res;
    -
    16823  }
    -
    16824  }
    -
    16825 
    -
    16826  *pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString);
    -
    16827  (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
    -
    16828  (*pAllocation)->SetUserData(this, pUserData);
    -
    16829  m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
    -
    16830  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    -
    16831  {
    -
    16832  FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
    -
    16833  }
    -
    16834 
    -
    16835  return VK_SUCCESS;
    -
    16836 }
    -
    16837 
    -
    16838 void VmaAllocator_T::GetBufferMemoryRequirements(
    -
    16839  VkBuffer hBuffer,
    -
    16840  VkMemoryRequirements& memReq,
    -
    16841  bool& requiresDedicatedAllocation,
    -
    16842  bool& prefersDedicatedAllocation) const
    -
    16843 {
    -
    16844 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16845  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16765  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    +
    16766  DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
    +
    16767  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    +
    16768  {
    +
    16769  dedicatedAllocations.PushBack(pAllocations[allocIndex]);
    +
    16770  }
    +
    16771  }
    +
    16772 
    +
    16773  VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
    +
    16774  }
    +
    16775  else
    +
    16776  {
    +
    16777  // Free all already created allocations.
    +
    16778  while(allocIndex--)
    +
    16779  {
    +
    16780  VmaAllocation currAlloc = pAllocations[allocIndex];
    +
    16781  VkDeviceMemory hMemory = currAlloc->GetMemory();
    +
    16782 
    +
    16783  /*
    +
    16784  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
    +
    16785  before vkFreeMemory.
    +
    16786 
    +
    16787  if(currAlloc->GetMappedData() != VMA_NULL)
    +
    16788  {
    +
    16789  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
    +
    16790  }
    +
    16791  */
    +
    16792 
    +
    16793  FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
    +
    16794  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize());
    +
    16795  currAlloc->SetUserData(this, VMA_NULL);
    +
    16796  m_AllocationObjectAllocator.Free(currAlloc);
    +
    16797  }
    +
    16798 
    +
    16799  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
    +
    16800  }
    +
    16801 
    +
    16802  return res;
    +
    16803 }
    +
    16804 
    +
    16805 VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
    +
    16806  VkDeviceSize size,
    +
    16807  VmaSuballocationType suballocType,
    +
    16808  uint32_t memTypeIndex,
    +
    16809  const VkMemoryAllocateInfo& allocInfo,
    +
    16810  bool map,
    +
    16811  bool isUserDataString,
    +
    16812  void* pUserData,
    +
    16813  VmaAllocation* pAllocation)
    +
    16814 {
    +
    16815  VkDeviceMemory hMemory = VK_NULL_HANDLE;
    +
    16816  VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
    +
    16817  if(res < 0)
    +
    16818  {
    +
    16819  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    +
    16820  return res;
    +
    16821  }
    +
    16822 
    +
    16823  void* pMappedData = VMA_NULL;
    +
    16824  if(map)
    +
    16825  {
    +
    16826  res = (*m_VulkanFunctions.vkMapMemory)(
    +
    16827  m_hDevice,
    +
    16828  hMemory,
    +
    16829  0,
    +
    16830  VK_WHOLE_SIZE,
    +
    16831  0,
    +
    16832  &pMappedData);
    +
    16833  if(res < 0)
    +
    16834  {
    +
    16835  VMA_DEBUG_LOG(" vkMapMemory FAILED");
    +
    16836  FreeVulkanMemory(memTypeIndex, size, hMemory);
    +
    16837  return res;
    +
    16838  }
    +
    16839  }
    +
    16840 
    +
    16841  *pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString);
    +
    16842  (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
    +
    16843  (*pAllocation)->SetUserData(this, pUserData);
    +
    16844  m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
    +
    16845  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    16846  {
    -
    16847  VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR };
    -
    16848  memReqInfo.buffer = hBuffer;
    +
    16847  FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
    +
    16848  }
    16849 
    -
    16850  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
    -
    16851 
    -
    16852  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
    -
    16853  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
    -
    16854 
    -
    16855  (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
    -
    16856 
    -
    16857  memReq = memReq2.memoryRequirements;
    -
    16858  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
    -
    16859  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
    -
    16860  }
    -
    16861  else
    -
    16862 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16863  {
    -
    16864  (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq);
    -
    16865  requiresDedicatedAllocation = false;
    -
    16866  prefersDedicatedAllocation = false;
    -
    16867  }
    -
    16868 }
    +
    16850  return VK_SUCCESS;
    +
    16851 }
    +
    16852 
    +
    16853 void VmaAllocator_T::GetBufferMemoryRequirements(
    +
    16854  VkBuffer hBuffer,
    +
    16855  VkMemoryRequirements& memReq,
    +
    16856  bool& requiresDedicatedAllocation,
    +
    16857  bool& prefersDedicatedAllocation) const
    +
    16858 {
    +
    16859 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16860  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16861  {
    +
    16862  VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR };
    +
    16863  memReqInfo.buffer = hBuffer;
    +
    16864 
    +
    16865  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
    +
    16866 
    +
    16867  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
    +
    16868  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
    16869 
    -
    16870 void VmaAllocator_T::GetImageMemoryRequirements(
    -
    16871  VkImage hImage,
    -
    16872  VkMemoryRequirements& memReq,
    -
    16873  bool& requiresDedicatedAllocation,
    -
    16874  bool& prefersDedicatedAllocation) const
    -
    16875 {
    -
    16876 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16877  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16870  (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
    +
    16871 
    +
    16872  memReq = memReq2.memoryRequirements;
    +
    16873  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
    +
    16874  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
    +
    16875  }
    +
    16876  else
    +
    16877 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    16878  {
    -
    16879  VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR };
    -
    16880  memReqInfo.image = hImage;
    -
    16881 
    -
    16882  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
    -
    16883 
    -
    16884  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
    -
    16885  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
    -
    16886 
    -
    16887  (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
    -
    16888 
    -
    16889  memReq = memReq2.memoryRequirements;
    -
    16890  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
    -
    16891  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
    -
    16892  }
    -
    16893  else
    -
    16894 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    -
    16895  {
    -
    16896  (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq);
    -
    16897  requiresDedicatedAllocation = false;
    -
    16898  prefersDedicatedAllocation = false;
    -
    16899  }
    -
    16900 }
    +
    16879  (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq);
    +
    16880  requiresDedicatedAllocation = false;
    +
    16881  prefersDedicatedAllocation = false;
    +
    16882  }
    +
    16883 }
    +
    16884 
    +
    16885 void VmaAllocator_T::GetImageMemoryRequirements(
    +
    16886  VkImage hImage,
    +
    16887  VkMemoryRequirements& memReq,
    +
    16888  bool& requiresDedicatedAllocation,
    +
    16889  bool& prefersDedicatedAllocation) const
    +
    16890 {
    +
    16891 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16892  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
    +
    16893  {
    +
    16894  VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR };
    +
    16895  memReqInfo.image = hImage;
    +
    16896 
    +
    16897  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
    +
    16898 
    +
    16899  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
    +
    16900  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
    16901 
    -
    16902 VkResult VmaAllocator_T::AllocateMemory(
    -
    16903  const VkMemoryRequirements& vkMemReq,
    -
    16904  bool requiresDedicatedAllocation,
    -
    16905  bool prefersDedicatedAllocation,
    -
    16906  VkBuffer dedicatedBuffer,
    -
    16907  VkBufferUsageFlags dedicatedBufferUsage,
    -
    16908  VkImage dedicatedImage,
    -
    16909  const VmaAllocationCreateInfo& createInfo,
    -
    16910  VmaSuballocationType suballocType,
    -
    16911  size_t allocationCount,
    -
    16912  VmaAllocation* pAllocations)
    -
    16913 {
    -
    16914  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
    -
    16915 
    -
    16916  VMA_ASSERT(VmaIsPow2(vkMemReq.alignment));
    -
    16917 
    -
    16918  if(vkMemReq.size == 0)
    -
    16919  {
    -
    16920  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    16921  }
    -
    16922  if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
    -
    16923  (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    -
    16924  {
    -
    16925  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
    -
    16926  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16927  }
    -
    16928  if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
    -
    16929  (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0)
    -
    16930  {
    -
    16931  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
    -
    16932  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16933  }
    -
    16934  if(requiresDedicatedAllocation)
    -
    16935  {
    -
    16936  if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    -
    16937  {
    -
    16938  VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
    -
    16939  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16940  }
    -
    16941  if(createInfo.pool != VK_NULL_HANDLE)
    -
    16942  {
    -
    16943  VMA_ASSERT(0 && "Pool specified while dedicated allocation is required.");
    -
    16944  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16945  }
    -
    16946  }
    -
    16947  if((createInfo.pool != VK_NULL_HANDLE) &&
    -
    16948  ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
    -
    16949  {
    -
    16950  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
    -
    16951  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    16952  }
    -
    16953 
    -
    16954  if(createInfo.pool != VK_NULL_HANDLE)
    -
    16955  {
    -
    16956  VmaAllocationCreateInfo createInfoForPool = createInfo;
    -
    16957  // If memory type is not HOST_VISIBLE, disable MAPPED.
    -
    16958  if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
    -
    16959  (m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    -
    16960  {
    -
    16961  createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
    -
    16962  }
    -
    16963 
    -
    16964  return createInfo.pool->m_BlockVector.Allocate(
    -
    16965  m_CurrentFrameIndex.load(),
    -
    16966  vkMemReq.size,
    -
    16967  vkMemReq.alignment,
    -
    16968  createInfoForPool,
    -
    16969  suballocType,
    -
    16970  allocationCount,
    -
    16971  pAllocations);
    -
    16972  }
    -
    16973  else
    -
    16974  {
    -
    16975  // Bit mask of memory Vulkan types acceptable for this allocation.
    -
    16976  uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
    -
    16977  uint32_t memTypeIndex = UINT32_MAX;
    -
    16978  VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
    -
    16979  if(res == VK_SUCCESS)
    -
    16980  {
    -
    16981  res = AllocateMemoryOfType(
    -
    16982  vkMemReq.size,
    -
    16983  vkMemReq.alignment,
    -
    16984  requiresDedicatedAllocation || prefersDedicatedAllocation,
    -
    16985  dedicatedBuffer,
    -
    16986  dedicatedBufferUsage,
    -
    16987  dedicatedImage,
    -
    16988  createInfo,
    -
    16989  memTypeIndex,
    -
    16990  suballocType,
    -
    16991  allocationCount,
    -
    16992  pAllocations);
    -
    16993  // Succeeded on first try.
    -
    16994  if(res == VK_SUCCESS)
    -
    16995  {
    -
    16996  return res;
    -
    16997  }
    -
    16998  // Allocation from this memory type failed. Try other compatible memory types.
    -
    16999  else
    -
    17000  {
    -
    17001  for(;;)
    -
    17002  {
    -
    17003  // Remove old memTypeIndex from list of possibilities.
    -
    17004  memoryTypeBits &= ~(1u << memTypeIndex);
    -
    17005  // Find alternative memTypeIndex.
    -
    17006  res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
    -
    17007  if(res == VK_SUCCESS)
    -
    17008  {
    -
    17009  res = AllocateMemoryOfType(
    -
    17010  vkMemReq.size,
    -
    17011  vkMemReq.alignment,
    -
    17012  requiresDedicatedAllocation || prefersDedicatedAllocation,
    -
    17013  dedicatedBuffer,
    -
    17014  dedicatedBufferUsage,
    -
    17015  dedicatedImage,
    -
    17016  createInfo,
    -
    17017  memTypeIndex,
    -
    17018  suballocType,
    -
    17019  allocationCount,
    -
    17020  pAllocations);
    -
    17021  // Allocation from this alternative memory type succeeded.
    -
    17022  if(res == VK_SUCCESS)
    -
    17023  {
    -
    17024  return res;
    -
    17025  }
    -
    17026  // else: Allocation from this memory type failed. Try next one - next loop iteration.
    -
    17027  }
    -
    17028  // No other matching memory type index could be found.
    -
    17029  else
    -
    17030  {
    -
    17031  // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
    -
    17032  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    17033  }
    -
    17034  }
    -
    17035  }
    -
    17036  }
    -
    17037  // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
    -
    17038  else
    -
    17039  return res;
    -
    17040  }
    -
    17041 }
    -
    17042 
    -
    17043 void VmaAllocator_T::FreeMemory(
    -
    17044  size_t allocationCount,
    -
    17045  const VmaAllocation* pAllocations)
    -
    17046 {
    -
    17047  VMA_ASSERT(pAllocations);
    -
    17048 
    -
    17049  for(size_t allocIndex = allocationCount; allocIndex--; )
    -
    17050  {
    -
    17051  VmaAllocation allocation = pAllocations[allocIndex];
    -
    17052 
    -
    17053  if(allocation != VK_NULL_HANDLE)
    -
    17054  {
    -
    17055  if(TouchAllocation(allocation))
    -
    17056  {
    -
    17057  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    -
    17058  {
    -
    17059  FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED);
    -
    17060  }
    -
    17061 
    -
    17062  switch(allocation->GetType())
    -
    17063  {
    -
    17064  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    -
    17065  {
    -
    17066  VmaBlockVector* pBlockVector = VMA_NULL;
    -
    17067  VmaPool hPool = allocation->GetBlock()->GetParentPool();
    -
    17068  if(hPool != VK_NULL_HANDLE)
    -
    17069  {
    -
    17070  pBlockVector = &hPool->m_BlockVector;
    -
    17071  }
    -
    17072  else
    -
    17073  {
    -
    17074  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    -
    17075  pBlockVector = m_pBlockVectors[memTypeIndex];
    -
    17076  }
    -
    17077  pBlockVector->Free(allocation);
    -
    17078  }
    -
    17079  break;
    -
    17080  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    -
    17081  FreeDedicatedMemory(allocation);
    -
    17082  break;
    -
    17083  default:
    -
    17084  VMA_ASSERT(0);
    -
    17085  }
    -
    17086  }
    -
    17087 
    -
    17088  // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes.
    -
    17089  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
    -
    17090  allocation->SetUserData(this, VMA_NULL);
    -
    17091  m_AllocationObjectAllocator.Free(allocation);
    -
    17092  }
    -
    17093  }
    -
    17094 }
    -
    17095 
    -
    17096 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
    -
    17097 {
    -
    17098  // Initialize.
    -
    17099  InitStatInfo(pStats->total);
    -
    17100  for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
    -
    17101  InitStatInfo(pStats->memoryType[i]);
    -
    17102  for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
    -
    17103  InitStatInfo(pStats->memoryHeap[i]);
    -
    17104 
    -
    17105  // Process default pools.
    -
    17106  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    17107  {
    -
    17108  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
    -
    17109  VMA_ASSERT(pBlockVector);
    -
    17110  pBlockVector->AddStats(pStats);
    -
    17111  }
    -
    17112 
    -
    17113  // Process custom pools.
    -
    17114  {
    -
    17115  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
    -
    17116  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
    -
    17117  {
    -
    17118  pool->m_BlockVector.AddStats(pStats);
    -
    17119  }
    -
    17120  }
    -
    17121 
    -
    17122  // Process dedicated allocations.
    -
    17123  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    17124  {
    -
    17125  const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
    -
    17126  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    -
    17127  DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
    -
    17128  for(VmaAllocation alloc = dedicatedAllocList.Front();
    -
    17129  alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
    -
    17130  {
    -
    17131  VmaStatInfo allocationStatInfo;
    -
    17132  alloc->DedicatedAllocCalcStatsInfo(allocationStatInfo);
    -
    17133  VmaAddStatInfo(pStats->total, allocationStatInfo);
    -
    17134  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
    -
    17135  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
    -
    17136  }
    -
    17137  }
    -
    17138 
    -
    17139  // Postprocess.
    -
    17140  VmaPostprocessCalcStatInfo(pStats->total);
    -
    17141  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
    -
    17142  VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
    -
    17143  for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
    -
    17144  VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
    -
    17145 }
    -
    17146 
    -
    17147 void VmaAllocator_T::GetBudget(VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount)
    -
    17148 {
    -
    17149 #if VMA_MEMORY_BUDGET
    -
    17150  if(m_UseExtMemoryBudget)
    -
    17151  {
    -
    17152  if(m_Budget.m_OperationsSinceBudgetFetch < 30)
    -
    17153  {
    -
    17154  VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex);
    -
    17155  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
    -
    17156  {
    -
    17157  const uint32_t heapIndex = firstHeap + i;
    -
    17158 
    -
    17159  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
    -
    17160  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
    +
    16902  (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
    +
    16903 
    +
    16904  memReq = memReq2.memoryRequirements;
    +
    16905  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
    +
    16906  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
    +
    16907  }
    +
    16908  else
    +
    16909 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
    +
    16910  {
    +
    16911  (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq);
    +
    16912  requiresDedicatedAllocation = false;
    +
    16913  prefersDedicatedAllocation = false;
    +
    16914  }
    +
    16915 }
    +
    16916 
    +
    16917 VkResult VmaAllocator_T::AllocateMemory(
    +
    16918  const VkMemoryRequirements& vkMemReq,
    +
    16919  bool requiresDedicatedAllocation,
    +
    16920  bool prefersDedicatedAllocation,
    +
    16921  VkBuffer dedicatedBuffer,
    +
    16922  VkBufferUsageFlags dedicatedBufferUsage,
    +
    16923  VkImage dedicatedImage,
    +
    16924  const VmaAllocationCreateInfo& createInfo,
    +
    16925  VmaSuballocationType suballocType,
    +
    16926  size_t allocationCount,
    +
    16927  VmaAllocation* pAllocations)
    +
    16928 {
    +
    16929  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
    +
    16930 
    +
    16931  VMA_ASSERT(VmaIsPow2(vkMemReq.alignment));
    +
    16932 
    +
    16933  if(vkMemReq.size == 0)
    +
    16934  {
    +
    16935  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    16936  }
    +
    16937  if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
    +
    16938  (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    +
    16939  {
    +
    16940  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
    +
    16941  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16942  }
    +
    16943  if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
    +
    16944  (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0)
    +
    16945  {
    +
    16946  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
    +
    16947  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16948  }
    +
    16949  if(requiresDedicatedAllocation)
    +
    16950  {
    +
    16951  if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
    +
    16952  {
    +
    16953  VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
    +
    16954  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16955  }
    +
    16956  if(createInfo.pool != VK_NULL_HANDLE)
    +
    16957  {
    +
    16958  VMA_ASSERT(0 && "Pool specified while dedicated allocation is required.");
    +
    16959  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16960  }
    +
    16961  }
    +
    16962  if((createInfo.pool != VK_NULL_HANDLE) &&
    +
    16963  ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
    +
    16964  {
    +
    16965  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
    +
    16966  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    16967  }
    +
    16968 
    +
    16969  if(createInfo.pool != VK_NULL_HANDLE)
    +
    16970  {
    +
    16971  VmaAllocationCreateInfo createInfoForPool = createInfo;
    +
    16972  // If memory type is not HOST_VISIBLE, disable MAPPED.
    +
    16973  if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
    +
    16974  (m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    +
    16975  {
    +
    16976  createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
    +
    16977  }
    +
    16978 
    +
    16979  return createInfo.pool->m_BlockVector.Allocate(
    +
    16980  m_CurrentFrameIndex.load(),
    +
    16981  vkMemReq.size,
    +
    16982  vkMemReq.alignment,
    +
    16983  createInfoForPool,
    +
    16984  suballocType,
    +
    16985  allocationCount,
    +
    16986  pAllocations);
    +
    16987  }
    +
    16988  else
    +
    16989  {
    +
    16990  // Bit mask of memory Vulkan types acceptable for this allocation.
    +
    16991  uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
    +
    16992  uint32_t memTypeIndex = UINT32_MAX;
    +
    16993  VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
    +
    16994  if(res == VK_SUCCESS)
    +
    16995  {
    +
    16996  res = AllocateMemoryOfType(
    +
    16997  vkMemReq.size,
    +
    16998  vkMemReq.alignment,
    +
    16999  requiresDedicatedAllocation || prefersDedicatedAllocation,
    +
    17000  dedicatedBuffer,
    +
    17001  dedicatedBufferUsage,
    +
    17002  dedicatedImage,
    +
    17003  createInfo,
    +
    17004  memTypeIndex,
    +
    17005  suballocType,
    +
    17006  allocationCount,
    +
    17007  pAllocations);
    +
    17008  // Succeeded on first try.
    +
    17009  if(res == VK_SUCCESS)
    +
    17010  {
    +
    17011  return res;
    +
    17012  }
    +
    17013  // Allocation from this memory type failed. Try other compatible memory types.
    +
    17014  else
    +
    17015  {
    +
    17016  for(;;)
    +
    17017  {
    +
    17018  // Remove old memTypeIndex from list of possibilities.
    +
    17019  memoryTypeBits &= ~(1u << memTypeIndex);
    +
    17020  // Find alternative memTypeIndex.
    +
    17021  res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
    +
    17022  if(res == VK_SUCCESS)
    +
    17023  {
    +
    17024  res = AllocateMemoryOfType(
    +
    17025  vkMemReq.size,
    +
    17026  vkMemReq.alignment,
    +
    17027  requiresDedicatedAllocation || prefersDedicatedAllocation,
    +
    17028  dedicatedBuffer,
    +
    17029  dedicatedBufferUsage,
    +
    17030  dedicatedImage,
    +
    17031  createInfo,
    +
    17032  memTypeIndex,
    +
    17033  suballocType,
    +
    17034  allocationCount,
    +
    17035  pAllocations);
    +
    17036  // Allocation from this alternative memory type succeeded.
    +
    17037  if(res == VK_SUCCESS)
    +
    17038  {
    +
    17039  return res;
    +
    17040  }
    +
    17041  // else: Allocation from this memory type failed. Try next one - next loop iteration.
    +
    17042  }
    +
    17043  // No other matching memory type index could be found.
    +
    17044  else
    +
    17045  {
    +
    17046  // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
    +
    17047  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    17048  }
    +
    17049  }
    +
    17050  }
    +
    17051  }
    +
    17052  // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
    +
    17053  else
    +
    17054  return res;
    +
    17055  }
    +
    17056 }
    +
    17057 
    +
    17058 void VmaAllocator_T::FreeMemory(
    +
    17059  size_t allocationCount,
    +
    17060  const VmaAllocation* pAllocations)
    +
    17061 {
    +
    17062  VMA_ASSERT(pAllocations);
    +
    17063 
    +
    17064  for(size_t allocIndex = allocationCount; allocIndex--; )
    +
    17065  {
    +
    17066  VmaAllocation allocation = pAllocations[allocIndex];
    +
    17067 
    +
    17068  if(allocation != VK_NULL_HANDLE)
    +
    17069  {
    +
    17070  if(TouchAllocation(allocation))
    +
    17071  {
    +
    17072  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
    +
    17073  {
    +
    17074  FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED);
    +
    17075  }
    +
    17076 
    +
    17077  switch(allocation->GetType())
    +
    17078  {
    +
    17079  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    +
    17080  {
    +
    17081  VmaBlockVector* pBlockVector = VMA_NULL;
    +
    17082  VmaPool hPool = allocation->GetBlock()->GetParentPool();
    +
    17083  if(hPool != VK_NULL_HANDLE)
    +
    17084  {
    +
    17085  pBlockVector = &hPool->m_BlockVector;
    +
    17086  }
    +
    17087  else
    +
    17088  {
    +
    17089  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    +
    17090  pBlockVector = m_pBlockVectors[memTypeIndex];
    +
    17091  }
    +
    17092  pBlockVector->Free(allocation);
    +
    17093  }
    +
    17094  break;
    +
    17095  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    +
    17096  FreeDedicatedMemory(allocation);
    +
    17097  break;
    +
    17098  default:
    +
    17099  VMA_ASSERT(0);
    +
    17100  }
    +
    17101  }
    +
    17102 
    +
    17103  // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes.
    +
    17104  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
    +
    17105  allocation->SetUserData(this, VMA_NULL);
    +
    17106  m_AllocationObjectAllocator.Free(allocation);
    +
    17107  }
    +
    17108  }
    +
    17109 }
    +
    17110 
    +
    17111 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
    +
    17112 {
    +
    17113  // Initialize.
    +
    17114  InitStatInfo(pStats->total);
    +
    17115  for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
    +
    17116  InitStatInfo(pStats->memoryType[i]);
    +
    17117  for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
    +
    17118  InitStatInfo(pStats->memoryHeap[i]);
    +
    17119 
    +
    17120  // Process default pools.
    +
    17121  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    17122  {
    +
    17123  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
    +
    17124  VMA_ASSERT(pBlockVector);
    +
    17125  pBlockVector->AddStats(pStats);
    +
    17126  }
    +
    17127 
    +
    17128  // Process custom pools.
    +
    17129  {
    +
    17130  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
    +
    17131  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
    +
    17132  {
    +
    17133  pool->m_BlockVector.AddStats(pStats);
    +
    17134  }
    +
    17135  }
    +
    17136 
    +
    17137  // Process dedicated allocations.
    +
    17138  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    17139  {
    +
    17140  const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
    +
    17141  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    +
    17142  DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
    +
    17143  for(VmaAllocation alloc = dedicatedAllocList.Front();
    +
    17144  alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
    +
    17145  {
    +
    17146  VmaStatInfo allocationStatInfo;
    +
    17147  alloc->DedicatedAllocCalcStatsInfo(allocationStatInfo);
    +
    17148  VmaAddStatInfo(pStats->total, allocationStatInfo);
    +
    17149  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
    +
    17150  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
    +
    17151  }
    +
    17152  }
    +
    17153 
    +
    17154  // Postprocess.
    +
    17155  VmaPostprocessCalcStatInfo(pStats->total);
    +
    17156  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
    +
    17157  VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
    +
    17158  for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
    +
    17159  VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
    +
    17160 }
    17161 
    -
    17162  if(m_Budget.m_VulkanUsage[heapIndex] + outBudget->blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex])
    -
    17163  {
    -
    17164  outBudget->usage = m_Budget.m_VulkanUsage[heapIndex] +
    -
    17165  outBudget->blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
    -
    17166  }
    -
    17167  else
    -
    17168  {
    -
    17169  outBudget->usage = 0;
    -
    17170  }
    -
    17171 
    -
    17172  // Have to take MIN with heap size because explicit HeapSizeLimit is included in it.
    -
    17173  outBudget->budget = VMA_MIN(
    -
    17174  m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size);
    -
    17175  }
    -
    17176  }
    -
    17177  else
    -
    17178  {
    -
    17179  UpdateVulkanBudget(); // Outside of mutex lock
    -
    17180  GetBudget(outBudget, firstHeap, heapCount); // Recursion
    -
    17181  }
    -
    17182  }
    -
    17183  else
    -
    17184 #endif
    -
    17185  {
    -
    17186  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
    -
    17187  {
    -
    17188  const uint32_t heapIndex = firstHeap + i;
    -
    17189 
    -
    17190  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
    -
    17191  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
    -
    17192 
    -
    17193  outBudget->usage = outBudget->blockBytes;
    -
    17194  outBudget->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
    -
    17195  }
    -
    17196  }
    -
    17197 }
    -
    17198 
    -
    17199 static const uint32_t VMA_VENDOR_ID_AMD = 4098;
    -
    17200 
    -
    17201 VkResult VmaAllocator_T::DefragmentationBegin(
    -
    17202  const VmaDefragmentationInfo2& info,
    -
    17203  VmaDefragmentationStats* pStats,
    -
    17204  VmaDefragmentationContext* pContext)
    -
    17205 {
    -
    17206  if(info.pAllocationsChanged != VMA_NULL)
    -
    17207  {
    -
    17208  memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
    -
    17209  }
    -
    17210 
    -
    17211  *pContext = vma_new(this, VmaDefragmentationContext_T)(
    -
    17212  this, m_CurrentFrameIndex.load(), info.flags, pStats);
    +
    17162 void VmaAllocator_T::GetBudget(VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount)
    +
    17163 {
    +
    17164 #if VMA_MEMORY_BUDGET
    +
    17165  if(m_UseExtMemoryBudget)
    +
    17166  {
    +
    17167  if(m_Budget.m_OperationsSinceBudgetFetch < 30)
    +
    17168  {
    +
    17169  VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex);
    +
    17170  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
    +
    17171  {
    +
    17172  const uint32_t heapIndex = firstHeap + i;
    +
    17173 
    +
    17174  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
    +
    17175  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
    +
    17176 
    +
    17177  if(m_Budget.m_VulkanUsage[heapIndex] + outBudget->blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex])
    +
    17178  {
    +
    17179  outBudget->usage = m_Budget.m_VulkanUsage[heapIndex] +
    +
    17180  outBudget->blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
    +
    17181  }
    +
    17182  else
    +
    17183  {
    +
    17184  outBudget->usage = 0;
    +
    17185  }
    +
    17186 
    +
    17187  // Have to take MIN with heap size because explicit HeapSizeLimit is included in it.
    +
    17188  outBudget->budget = VMA_MIN(
    +
    17189  m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size);
    +
    17190  }
    +
    17191  }
    +
    17192  else
    +
    17193  {
    +
    17194  UpdateVulkanBudget(); // Outside of mutex lock
    +
    17195  GetBudget(outBudget, firstHeap, heapCount); // Recursion
    +
    17196  }
    +
    17197  }
    +
    17198  else
    +
    17199 #endif
    +
    17200  {
    +
    17201  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
    +
    17202  {
    +
    17203  const uint32_t heapIndex = firstHeap + i;
    +
    17204 
    +
    17205  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
    +
    17206  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
    +
    17207 
    +
    17208  outBudget->usage = outBudget->blockBytes;
    +
    17209  outBudget->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
    +
    17210  }
    +
    17211  }
    +
    17212 }
    17213 
    -
    17214  (*pContext)->AddPools(info.poolCount, info.pPools);
    -
    17215  (*pContext)->AddAllocations(
    -
    17216  info.allocationCount, info.pAllocations, info.pAllocationsChanged);
    -
    17217 
    -
    17218  VkResult res = (*pContext)->Defragment(
    -
    17219  info.maxCpuBytesToMove, info.maxCpuAllocationsToMove,
    -
    17220  info.maxGpuBytesToMove, info.maxGpuAllocationsToMove,
    -
    17221  info.commandBuffer, pStats, info.flags);
    -
    17222 
    -
    17223  if(res != VK_NOT_READY)
    -
    17224  {
    -
    17225  vma_delete(this, *pContext);
    -
    17226  *pContext = VMA_NULL;
    -
    17227  }
    +
    17214 static const uint32_t VMA_VENDOR_ID_AMD = 4098;
    +
    17215 
    +
    17216 VkResult VmaAllocator_T::DefragmentationBegin(
    +
    17217  const VmaDefragmentationInfo2& info,
    +
    17218  VmaDefragmentationStats* pStats,
    +
    17219  VmaDefragmentationContext* pContext)
    +
    17220 {
    +
    17221  if(info.pAllocationsChanged != VMA_NULL)
    +
    17222  {
    +
    17223  memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
    +
    17224  }
    +
    17225 
    +
    17226  *pContext = vma_new(this, VmaDefragmentationContext_T)(
    +
    17227  this, m_CurrentFrameIndex.load(), info.flags, pStats);
    17228 
    -
    17229  return res;
    -
    17230 }
    -
    17231 
    -
    17232 VkResult VmaAllocator_T::DefragmentationEnd(
    -
    17233  VmaDefragmentationContext context)
    -
    17234 {
    -
    17235  vma_delete(this, context);
    -
    17236  return VK_SUCCESS;
    -
    17237 }
    -
    17238 
    -
    17239 VkResult VmaAllocator_T::DefragmentationPassBegin(
    -
    17240  VmaDefragmentationPassInfo* pInfo,
    -
    17241  VmaDefragmentationContext context)
    -
    17242 {
    -
    17243  return context->DefragmentPassBegin(pInfo);
    -
    17244 }
    -
    17245 VkResult VmaAllocator_T::DefragmentationPassEnd(
    -
    17246  VmaDefragmentationContext context)
    -
    17247 {
    -
    17248  return context->DefragmentPassEnd();
    -
    17249 
    -
    17250 }
    -
    17251 
    -
    17252 void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
    -
    17253 {
    -
    17254  if(hAllocation->CanBecomeLost())
    -
    17255  {
    -
    17256  /*
    -
    17257  Warning: This is a carefully designed algorithm.
    -
    17258  Do not modify unless you really know what you're doing :)
    -
    17259  */
    -
    17260  const uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    -
    17261  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    -
    17262  for(;;)
    -
    17263  {
    -
    17264  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
    -
    17265  {
    -
    17266  pAllocationInfo->memoryType = UINT32_MAX;
    -
    17267  pAllocationInfo->deviceMemory = VK_NULL_HANDLE;
    -
    17268  pAllocationInfo->offset = 0;
    -
    17269  pAllocationInfo->size = hAllocation->GetSize();
    -
    17270  pAllocationInfo->pMappedData = VMA_NULL;
    -
    17271  pAllocationInfo->pUserData = hAllocation->GetUserData();
    -
    17272  return;
    -
    17273  }
    -
    17274  else if(localLastUseFrameIndex == localCurrFrameIndex)
    -
    17275  {
    -
    17276  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
    -
    17277  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
    -
    17278  pAllocationInfo->offset = hAllocation->GetOffset();
    -
    17279  pAllocationInfo->size = hAllocation->GetSize();
    -
    17280  pAllocationInfo->pMappedData = VMA_NULL;
    -
    17281  pAllocationInfo->pUserData = hAllocation->GetUserData();
    -
    17282  return;
    -
    17283  }
    -
    17284  else // Last use time earlier than current time.
    -
    17285  {
    -
    17286  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    -
    17287  {
    -
    17288  localLastUseFrameIndex = localCurrFrameIndex;
    -
    17289  }
    -
    17290  }
    -
    17291  }
    -
    17292  }
    -
    17293  else
    -
    17294  {
    -
    17295 #if VMA_STATS_STRING_ENABLED
    -
    17296  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    -
    17297  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    -
    17298  for(;;)
    -
    17299  {
    -
    17300  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
    -
    17301  if(localLastUseFrameIndex == localCurrFrameIndex)
    -
    17302  {
    -
    17303  break;
    -
    17304  }
    -
    17305  else // Last use time earlier than current time.
    -
    17306  {
    -
    17307  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    -
    17308  {
    -
    17309  localLastUseFrameIndex = localCurrFrameIndex;
    -
    17310  }
    -
    17311  }
    -
    17312  }
    -
    17313 #endif
    -
    17314 
    -
    17315  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
    -
    17316  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
    -
    17317  pAllocationInfo->offset = hAllocation->GetOffset();
    -
    17318  pAllocationInfo->size = hAllocation->GetSize();
    -
    17319  pAllocationInfo->pMappedData = hAllocation->GetMappedData();
    -
    17320  pAllocationInfo->pUserData = hAllocation->GetUserData();
    -
    17321  }
    -
    17322 }
    -
    17323 
    -
    17324 bool VmaAllocator_T::TouchAllocation(VmaAllocation hAllocation)
    -
    17325 {
    -
    17326  // This is a stripped-down version of VmaAllocator_T::GetAllocationInfo.
    -
    17327  if(hAllocation->CanBecomeLost())
    -
    17328  {
    -
    17329  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    -
    17330  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    -
    17331  for(;;)
    -
    17332  {
    -
    17333  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
    -
    17334  {
    -
    17335  return false;
    -
    17336  }
    -
    17337  else if(localLastUseFrameIndex == localCurrFrameIndex)
    -
    17338  {
    -
    17339  return true;
    -
    17340  }
    -
    17341  else // Last use time earlier than current time.
    -
    17342  {
    -
    17343  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    -
    17344  {
    -
    17345  localLastUseFrameIndex = localCurrFrameIndex;
    -
    17346  }
    -
    17347  }
    -
    17348  }
    -
    17349  }
    -
    17350  else
    -
    17351  {
    -
    17352 #if VMA_STATS_STRING_ENABLED
    -
    17353  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    -
    17354  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    -
    17355  for(;;)
    -
    17356  {
    -
    17357  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
    -
    17358  if(localLastUseFrameIndex == localCurrFrameIndex)
    -
    17359  {
    -
    17360  break;
    -
    17361  }
    -
    17362  else // Last use time earlier than current time.
    -
    17363  {
    -
    17364  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    -
    17365  {
    -
    17366  localLastUseFrameIndex = localCurrFrameIndex;
    -
    17367  }
    -
    17368  }
    -
    17369  }
    -
    17370 #endif
    -
    17371 
    -
    17372  return true;
    -
    17373  }
    -
    17374 }
    -
    17375 
    -
    17376 VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool)
    -
    17377 {
    -
    17378  VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags);
    -
    17379 
    -
    17380  VmaPoolCreateInfo newCreateInfo = *pCreateInfo;
    -
    17381 
    -
    17382  // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash.
    -
    17383  if(pCreateInfo->pMemoryAllocateNext)
    -
    17384  {
    -
    17385  VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0);
    -
    17386  }
    -
    17387 
    -
    17388  if(newCreateInfo.maxBlockCount == 0)
    -
    17389  {
    -
    17390  newCreateInfo.maxBlockCount = SIZE_MAX;
    -
    17391  }
    -
    17392  if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount)
    -
    17393  {
    -
    17394  return VK_ERROR_INITIALIZATION_FAILED;
    -
    17395  }
    -
    17396  // Memory type index out of range or forbidden.
    -
    17397  if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() ||
    -
    17398  ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0)
    +
    17229  (*pContext)->AddPools(info.poolCount, info.pPools);
    +
    17230  (*pContext)->AddAllocations(
    +
    17231  info.allocationCount, info.pAllocations, info.pAllocationsChanged);
    +
    17232 
    +
    17233  VkResult res = (*pContext)->Defragment(
    +
    17234  info.maxCpuBytesToMove, info.maxCpuAllocationsToMove,
    +
    17235  info.maxGpuBytesToMove, info.maxGpuAllocationsToMove,
    +
    17236  info.commandBuffer, pStats, info.flags);
    +
    17237 
    +
    17238  if(res != VK_NOT_READY)
    +
    17239  {
    +
    17240  vma_delete(this, *pContext);
    +
    17241  *pContext = VMA_NULL;
    +
    17242  }
    +
    17243 
    +
    17244  return res;
    +
    17245 }
    +
    17246 
    +
    17247 VkResult VmaAllocator_T::DefragmentationEnd(
    +
    17248  VmaDefragmentationContext context)
    +
    17249 {
    +
    17250  vma_delete(this, context);
    +
    17251  return VK_SUCCESS;
    +
    17252 }
    +
    17253 
    +
    17254 VkResult VmaAllocator_T::DefragmentationPassBegin(
    +
    17255  VmaDefragmentationPassInfo* pInfo,
    +
    17256  VmaDefragmentationContext context)
    +
    17257 {
    +
    17258  return context->DefragmentPassBegin(pInfo);
    +
    17259 }
    +
    17260 VkResult VmaAllocator_T::DefragmentationPassEnd(
    +
    17261  VmaDefragmentationContext context)
    +
    17262 {
    +
    17263  return context->DefragmentPassEnd();
    +
    17264 
    +
    17265 }
    +
    17266 
    +
    17267 void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
    +
    17268 {
    +
    17269  if(hAllocation->CanBecomeLost())
    +
    17270  {
    +
    17271  /*
    +
    17272  Warning: This is a carefully designed algorithm.
    +
    17273  Do not modify unless you really know what you're doing :)
    +
    17274  */
    +
    17275  const uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    +
    17276  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    +
    17277  for(;;)
    +
    17278  {
    +
    17279  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
    +
    17280  {
    +
    17281  pAllocationInfo->memoryType = UINT32_MAX;
    +
    17282  pAllocationInfo->deviceMemory = VK_NULL_HANDLE;
    +
    17283  pAllocationInfo->offset = 0;
    +
    17284  pAllocationInfo->size = hAllocation->GetSize();
    +
    17285  pAllocationInfo->pMappedData = VMA_NULL;
    +
    17286  pAllocationInfo->pUserData = hAllocation->GetUserData();
    +
    17287  return;
    +
    17288  }
    +
    17289  else if(localLastUseFrameIndex == localCurrFrameIndex)
    +
    17290  {
    +
    17291  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
    +
    17292  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
    +
    17293  pAllocationInfo->offset = hAllocation->GetOffset();
    +
    17294  pAllocationInfo->size = hAllocation->GetSize();
    +
    17295  pAllocationInfo->pMappedData = VMA_NULL;
    +
    17296  pAllocationInfo->pUserData = hAllocation->GetUserData();
    +
    17297  return;
    +
    17298  }
    +
    17299  else // Last use time earlier than current time.
    +
    17300  {
    +
    17301  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    +
    17302  {
    +
    17303  localLastUseFrameIndex = localCurrFrameIndex;
    +
    17304  }
    +
    17305  }
    +
    17306  }
    +
    17307  }
    +
    17308  else
    +
    17309  {
    +
    17310 #if VMA_STATS_STRING_ENABLED
    +
    17311  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    +
    17312  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    +
    17313  for(;;)
    +
    17314  {
    +
    17315  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
    +
    17316  if(localLastUseFrameIndex == localCurrFrameIndex)
    +
    17317  {
    +
    17318  break;
    +
    17319  }
    +
    17320  else // Last use time earlier than current time.
    +
    17321  {
    +
    17322  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    +
    17323  {
    +
    17324  localLastUseFrameIndex = localCurrFrameIndex;
    +
    17325  }
    +
    17326  }
    +
    17327  }
    +
    17328 #endif
    +
    17329 
    +
    17330  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
    +
    17331  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
    +
    17332  pAllocationInfo->offset = hAllocation->GetOffset();
    +
    17333  pAllocationInfo->size = hAllocation->GetSize();
    +
    17334  pAllocationInfo->pMappedData = hAllocation->GetMappedData();
    +
    17335  pAllocationInfo->pUserData = hAllocation->GetUserData();
    +
    17336  }
    +
    17337 }
    +
    17338 
    +
    17339 bool VmaAllocator_T::TouchAllocation(VmaAllocation hAllocation)
    +
    17340 {
    +
    17341  // This is a stripped-down version of VmaAllocator_T::GetAllocationInfo.
    +
    17342  if(hAllocation->CanBecomeLost())
    +
    17343  {
    +
    17344  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    +
    17345  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    +
    17346  for(;;)
    +
    17347  {
    +
    17348  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
    +
    17349  {
    +
    17350  return false;
    +
    17351  }
    +
    17352  else if(localLastUseFrameIndex == localCurrFrameIndex)
    +
    17353  {
    +
    17354  return true;
    +
    17355  }
    +
    17356  else // Last use time earlier than current time.
    +
    17357  {
    +
    17358  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    +
    17359  {
    +
    17360  localLastUseFrameIndex = localCurrFrameIndex;
    +
    17361  }
    +
    17362  }
    +
    17363  }
    +
    17364  }
    +
    17365  else
    +
    17366  {
    +
    17367 #if VMA_STATS_STRING_ENABLED
    +
    17368  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
    +
    17369  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
    +
    17370  for(;;)
    +
    17371  {
    +
    17372  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
    +
    17373  if(localLastUseFrameIndex == localCurrFrameIndex)
    +
    17374  {
    +
    17375  break;
    +
    17376  }
    +
    17377  else // Last use time earlier than current time.
    +
    17378  {
    +
    17379  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
    +
    17380  {
    +
    17381  localLastUseFrameIndex = localCurrFrameIndex;
    +
    17382  }
    +
    17383  }
    +
    17384  }
    +
    17385 #endif
    +
    17386 
    +
    17387  return true;
    +
    17388  }
    +
    17389 }
    +
    17390 
    +
    17391 VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool)
    +
    17392 {
    +
    17393  VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags);
    +
    17394 
    +
    17395  VmaPoolCreateInfo newCreateInfo = *pCreateInfo;
    +
    17396 
    +
    17397  // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash.
    +
    17398  if(pCreateInfo->pMemoryAllocateNext)
    17399  {
    -
    17400  return VK_ERROR_FEATURE_NOT_PRESENT;
    +
    17400  VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0);
    17401  }
    -
    17402  if(newCreateInfo.minAllocationAlignment > 0)
    -
    17403  {
    -
    17404  VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment));
    -
    17405  }
    -
    17406 
    -
    17407  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
    -
    17408 
    -
    17409  *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize);
    -
    17410 
    -
    17411  VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks();
    -
    17412  if(res != VK_SUCCESS)
    -
    17413  {
    -
    17414  vma_delete(this, *pPool);
    -
    17415  *pPool = VMA_NULL;
    -
    17416  return res;
    -
    17417  }
    -
    17418 
    -
    17419  // Add to m_Pools.
    -
    17420  {
    -
    17421  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
    -
    17422  (*pPool)->SetId(m_NextPoolId++);
    -
    17423  m_Pools.PushBack(*pPool);
    -
    17424  }
    +
    17402 
    +
    17403  if(newCreateInfo.maxBlockCount == 0)
    +
    17404  {
    +
    17405  newCreateInfo.maxBlockCount = SIZE_MAX;
    +
    17406  }
    +
    17407  if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount)
    +
    17408  {
    +
    17409  return VK_ERROR_INITIALIZATION_FAILED;
    +
    17410  }
    +
    17411  // Memory type index out of range or forbidden.
    +
    17412  if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() ||
    +
    17413  ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0)
    +
    17414  {
    +
    17415  return VK_ERROR_FEATURE_NOT_PRESENT;
    +
    17416  }
    +
    17417  if(newCreateInfo.minAllocationAlignment > 0)
    +
    17418  {
    +
    17419  VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment));
    +
    17420  }
    +
    17421 
    +
    17422  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
    +
    17423 
    +
    17424  *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize);
    17425 
    -
    17426  return VK_SUCCESS;
    -
    17427 }
    -
    17428 
    -
    17429 void VmaAllocator_T::DestroyPool(VmaPool pool)
    -
    17430 {
    -
    17431  // Remove from m_Pools.
    -
    17432  {
    -
    17433  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
    -
    17434  m_Pools.Remove(pool);
    -
    17435  }
    -
    17436 
    -
    17437  vma_delete(this, pool);
    -
    17438 }
    -
    17439 
    -
    17440 void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats)
    -
    17441 {
    -
    17442  pool->m_BlockVector.GetPoolStats(pPoolStats);
    -
    17443 }
    -
    17444 
    -
    17445 void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex)
    -
    17446 {
    -
    17447  m_CurrentFrameIndex.store(frameIndex);
    -
    17448 
    -
    17449 #if VMA_MEMORY_BUDGET
    -
    17450  if(m_UseExtMemoryBudget)
    -
    17451  {
    -
    17452  UpdateVulkanBudget();
    -
    17453  }
    -
    17454 #endif // #if VMA_MEMORY_BUDGET
    -
    17455 }
    -
    17456 
    -
    17457 void VmaAllocator_T::MakePoolAllocationsLost(
    -
    17458  VmaPool hPool,
    -
    17459  size_t* pLostAllocationCount)
    -
    17460 {
    -
    17461  hPool->m_BlockVector.MakePoolAllocationsLost(
    -
    17462  m_CurrentFrameIndex.load(),
    -
    17463  pLostAllocationCount);
    -
    17464 }
    -
    17465 
    -
    17466 VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool)
    -
    17467 {
    -
    17468  return hPool->m_BlockVector.CheckCorruption();
    -
    17469 }
    -
    17470 
    -
    17471 VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits)
    -
    17472 {
    -
    17473  VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT;
    -
    17474 
    -
    17475  // Process default pools.
    -
    17476  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    17477  {
    -
    17478  if(((1u << memTypeIndex) & memoryTypeBits) != 0)
    -
    17479  {
    -
    17480  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
    -
    17481  VMA_ASSERT(pBlockVector);
    -
    17482  VkResult localRes = pBlockVector->CheckCorruption();
    -
    17483  switch(localRes)
    -
    17484  {
    -
    17485  case VK_ERROR_FEATURE_NOT_PRESENT:
    -
    17486  break;
    -
    17487  case VK_SUCCESS:
    -
    17488  finalRes = VK_SUCCESS;
    -
    17489  break;
    -
    17490  default:
    -
    17491  return localRes;
    -
    17492  }
    -
    17493  }
    -
    17494  }
    -
    17495 
    -
    17496  // Process custom pools.
    -
    17497  {
    -
    17498  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
    -
    17499  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
    -
    17500  {
    -
    17501  if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0)
    -
    17502  {
    -
    17503  VkResult localRes = pool->m_BlockVector.CheckCorruption();
    -
    17504  switch(localRes)
    -
    17505  {
    -
    17506  case VK_ERROR_FEATURE_NOT_PRESENT:
    -
    17507  break;
    -
    17508  case VK_SUCCESS:
    -
    17509  finalRes = VK_SUCCESS;
    -
    17510  break;
    -
    17511  default:
    -
    17512  return localRes;
    -
    17513  }
    -
    17514  }
    -
    17515  }
    -
    17516  }
    -
    17517 
    -
    17518  return finalRes;
    -
    17519 }
    -
    17520 
    -
    17521 void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
    -
    17522 {
    -
    17523  *pAllocation = m_AllocationObjectAllocator.Allocate(VMA_FRAME_INDEX_LOST, false);
    -
    17524  (*pAllocation)->InitLost();
    -
    17525 }
    -
    17526 
    -
    17527 // An object that increments given atomic but decrements it back in the destructor unless Commit() is called.
    -
    17528 template<typename T>
    -
    17529 struct AtomicTransactionalIncrement
    -
    17530 {
    -
    17531 public:
    -
    17532  typedef std::atomic<T> AtomicT;
    -
    17533  ~AtomicTransactionalIncrement()
    -
    17534  {
    -
    17535  if(m_Atomic)
    -
    17536  --(*m_Atomic);
    -
    17537  }
    -
    17538  T Increment(AtomicT* atomic)
    -
    17539  {
    -
    17540  m_Atomic = atomic;
    -
    17541  return m_Atomic->fetch_add(1);
    -
    17542  }
    -
    17543  void Commit()
    -
    17544  {
    -
    17545  m_Atomic = nullptr;
    -
    17546  }
    -
    17547 
    -
    17548 private:
    -
    17549  AtomicT* m_Atomic = nullptr;
    -
    17550 };
    -
    17551 
    -
    17552 VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
    -
    17553 {
    -
    17554  AtomicTransactionalIncrement<uint32_t> deviceMemoryCountIncrement;
    -
    17555  const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount);
    -
    17556 #if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
    -
    17557  if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount)
    -
    17558  {
    -
    17559  return VK_ERROR_TOO_MANY_OBJECTS;
    -
    17560  }
    -
    17561 #endif
    +
    17426  VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks();
    +
    17427  if(res != VK_SUCCESS)
    +
    17428  {
    +
    17429  vma_delete(this, *pPool);
    +
    17430  *pPool = VMA_NULL;
    +
    17431  return res;
    +
    17432  }
    +
    17433 
    +
    17434  // Add to m_Pools.
    +
    17435  {
    +
    17436  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
    +
    17437  (*pPool)->SetId(m_NextPoolId++);
    +
    17438  m_Pools.PushBack(*pPool);
    +
    17439  }
    +
    17440 
    +
    17441  return VK_SUCCESS;
    +
    17442 }
    +
    17443 
    +
    17444 void VmaAllocator_T::DestroyPool(VmaPool pool)
    +
    17445 {
    +
    17446  // Remove from m_Pools.
    +
    17447  {
    +
    17448  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
    +
    17449  m_Pools.Remove(pool);
    +
    17450  }
    +
    17451 
    +
    17452  vma_delete(this, pool);
    +
    17453 }
    +
    17454 
    +
    17455 void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats)
    +
    17456 {
    +
    17457  pool->m_BlockVector.GetPoolStats(pPoolStats);
    +
    17458 }
    +
    17459 
    +
    17460 void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex)
    +
    17461 {
    +
    17462  m_CurrentFrameIndex.store(frameIndex);
    +
    17463 
    +
    17464 #if VMA_MEMORY_BUDGET
    +
    17465  if(m_UseExtMemoryBudget)
    +
    17466  {
    +
    17467  UpdateVulkanBudget();
    +
    17468  }
    +
    17469 #endif // #if VMA_MEMORY_BUDGET
    +
    17470 }
    +
    17471 
    +
    17472 void VmaAllocator_T::MakePoolAllocationsLost(
    +
    17473  VmaPool hPool,
    +
    17474  size_t* pLostAllocationCount)
    +
    17475 {
    +
    17476  hPool->m_BlockVector.MakePoolAllocationsLost(
    +
    17477  m_CurrentFrameIndex.load(),
    +
    17478  pLostAllocationCount);
    +
    17479 }
    +
    17480 
    +
    17481 VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool)
    +
    17482 {
    +
    17483  return hPool->m_BlockVector.CheckCorruption();
    +
    17484 }
    +
    17485 
    +
    17486 VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits)
    +
    17487 {
    +
    17488  VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT;
    +
    17489 
    +
    17490  // Process default pools.
    +
    17491  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    17492  {
    +
    17493  if(((1u << memTypeIndex) & memoryTypeBits) != 0)
    +
    17494  {
    +
    17495  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
    +
    17496  VMA_ASSERT(pBlockVector);
    +
    17497  VkResult localRes = pBlockVector->CheckCorruption();
    +
    17498  switch(localRes)
    +
    17499  {
    +
    17500  case VK_ERROR_FEATURE_NOT_PRESENT:
    +
    17501  break;
    +
    17502  case VK_SUCCESS:
    +
    17503  finalRes = VK_SUCCESS;
    +
    17504  break;
    +
    17505  default:
    +
    17506  return localRes;
    +
    17507  }
    +
    17508  }
    +
    17509  }
    +
    17510 
    +
    17511  // Process custom pools.
    +
    17512  {
    +
    17513  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
    +
    17514  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
    +
    17515  {
    +
    17516  if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0)
    +
    17517  {
    +
    17518  VkResult localRes = pool->m_BlockVector.CheckCorruption();
    +
    17519  switch(localRes)
    +
    17520  {
    +
    17521  case VK_ERROR_FEATURE_NOT_PRESENT:
    +
    17522  break;
    +
    17523  case VK_SUCCESS:
    +
    17524  finalRes = VK_SUCCESS;
    +
    17525  break;
    +
    17526  default:
    +
    17527  return localRes;
    +
    17528  }
    +
    17529  }
    +
    17530  }
    +
    17531  }
    +
    17532 
    +
    17533  return finalRes;
    +
    17534 }
    +
    17535 
    +
    17536 void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
    +
    17537 {
    +
    17538  *pAllocation = m_AllocationObjectAllocator.Allocate(VMA_FRAME_INDEX_LOST, false);
    +
    17539  (*pAllocation)->InitLost();
    +
    17540 }
    +
    17541 
    +
    17542 // An object that increments given atomic but decrements it back in the destructor unless Commit() is called.
    +
    17543 template<typename T>
    +
    17544 struct AtomicTransactionalIncrement
    +
    17545 {
    +
    17546 public:
    +
    17547  typedef std::atomic<T> AtomicT;
    +
    17548  ~AtomicTransactionalIncrement()
    +
    17549  {
    +
    17550  if(m_Atomic)
    +
    17551  --(*m_Atomic);
    +
    17552  }
    +
    17553  T Increment(AtomicT* atomic)
    +
    17554  {
    +
    17555  m_Atomic = atomic;
    +
    17556  return m_Atomic->fetch_add(1);
    +
    17557  }
    +
    17558  void Commit()
    +
    17559  {
    +
    17560  m_Atomic = nullptr;
    +
    17561  }
    17562 
    -
    17563  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
    -
    17564 
    -
    17565  // HeapSizeLimit is in effect for this heap.
    -
    17566  if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0)
    -
    17567  {
    -
    17568  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
    -
    17569  VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex];
    -
    17570  for(;;)
    -
    17571  {
    -
    17572  const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize;
    -
    17573  if(blockBytesAfterAllocation > heapSize)
    -
    17574  {
    -
    17575  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    -
    17576  }
    -
    17577  if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation))
    -
    17578  {
    -
    17579  break;
    -
    17580  }
    -
    17581  }
    -
    17582  }
    -
    17583  else
    -
    17584  {
    -
    17585  m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize;
    -
    17586  }
    -
    17587 
    -
    17588  // VULKAN CALL vkAllocateMemory.
    -
    17589  VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
    -
    17590 
    -
    17591  if(res == VK_SUCCESS)
    -
    17592  {
    -
    17593 #if VMA_MEMORY_BUDGET
    -
    17594  ++m_Budget.m_OperationsSinceBudgetFetch;
    -
    17595 #endif
    -
    17596 
    -
    17597  // Informative callback.
    -
    17598  if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
    -
    17599  {
    -
    17600  (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData);
    -
    17601  }
    +
    17563 private:
    +
    17564  AtomicT* m_Atomic = nullptr;
    +
    17565 };
    +
    17566 
    +
    17567 VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
    +
    17568 {
    +
    17569  AtomicTransactionalIncrement<uint32_t> deviceMemoryCountIncrement;
    +
    17570  const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount);
    +
    17571 #if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
    +
    17572  if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount)
    +
    17573  {
    +
    17574  return VK_ERROR_TOO_MANY_OBJECTS;
    +
    17575  }
    +
    17576 #endif
    +
    17577 
    +
    17578  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
    +
    17579 
    +
    17580  // HeapSizeLimit is in effect for this heap.
    +
    17581  if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0)
    +
    17582  {
    +
    17583  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
    +
    17584  VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex];
    +
    17585  for(;;)
    +
    17586  {
    +
    17587  const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize;
    +
    17588  if(blockBytesAfterAllocation > heapSize)
    +
    17589  {
    +
    17590  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    +
    17591  }
    +
    17592  if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation))
    +
    17593  {
    +
    17594  break;
    +
    17595  }
    +
    17596  }
    +
    17597  }
    +
    17598  else
    +
    17599  {
    +
    17600  m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize;
    +
    17601  }
    17602 
    -
    17603  deviceMemoryCountIncrement.Commit();
    -
    17604  }
    -
    17605  else
    -
    17606  {
    -
    17607  m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize;
    -
    17608  }
    -
    17609 
    -
    17610  return res;
    -
    17611 }
    -
    17612 
    -
    17613 void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory)
    -
    17614 {
    -
    17615  // Informative callback.
    -
    17616  if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
    -
    17617  {
    -
    17618  (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData);
    +
    17603  // VULKAN CALL vkAllocateMemory.
    +
    17604  VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
    +
    17605 
    +
    17606  if(res == VK_SUCCESS)
    +
    17607  {
    +
    17608 #if VMA_MEMORY_BUDGET
    +
    17609  ++m_Budget.m_OperationsSinceBudgetFetch;
    +
    17610 #endif
    +
    17611 
    +
    17612  // Informative callback.
    +
    17613  if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
    +
    17614  {
    +
    17615  (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData);
    +
    17616  }
    +
    17617 
    +
    17618  deviceMemoryCountIncrement.Commit();
    17619  }
    -
    17620 
    -
    17621  // VULKAN CALL vkFreeMemory.
    -
    17622  (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
    -
    17623 
    -
    17624  m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
    -
    17625 
    -
    17626  --m_DeviceMemoryCount;
    -
    17627 }
    -
    17628 
    -
    17629 VkResult VmaAllocator_T::BindVulkanBuffer(
    -
    17630  VkDeviceMemory memory,
    -
    17631  VkDeviceSize memoryOffset,
    -
    17632  VkBuffer buffer,
    -
    17633  const void* pNext)
    -
    17634 {
    -
    17635  if(pNext != VMA_NULL)
    -
    17636  {
    -
    17637 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
    -
    17638  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
    -
    17639  m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL)
    -
    17640  {
    -
    17641  VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR };
    -
    17642  bindBufferMemoryInfo.pNext = pNext;
    -
    17643  bindBufferMemoryInfo.buffer = buffer;
    -
    17644  bindBufferMemoryInfo.memory = memory;
    -
    17645  bindBufferMemoryInfo.memoryOffset = memoryOffset;
    -
    17646  return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
    -
    17647  }
    -
    17648  else
    -
    17649 #endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
    -
    17650  {
    -
    17651  return VK_ERROR_EXTENSION_NOT_PRESENT;
    -
    17652  }
    -
    17653  }
    -
    17654  else
    -
    17655  {
    -
    17656  return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset);
    -
    17657  }
    -
    17658 }
    -
    17659 
    -
    17660 VkResult VmaAllocator_T::BindVulkanImage(
    -
    17661  VkDeviceMemory memory,
    -
    17662  VkDeviceSize memoryOffset,
    -
    17663  VkImage image,
    -
    17664  const void* pNext)
    -
    17665 {
    -
    17666  if(pNext != VMA_NULL)
    -
    17667  {
    -
    17668 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
    -
    17669  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
    -
    17670  m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL)
    -
    17671  {
    -
    17672  VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR };
    -
    17673  bindBufferMemoryInfo.pNext = pNext;
    -
    17674  bindBufferMemoryInfo.image = image;
    -
    17675  bindBufferMemoryInfo.memory = memory;
    -
    17676  bindBufferMemoryInfo.memoryOffset = memoryOffset;
    -
    17677  return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
    -
    17678  }
    -
    17679  else
    -
    17680 #endif // #if VMA_BIND_MEMORY2
    -
    17681  {
    -
    17682  return VK_ERROR_EXTENSION_NOT_PRESENT;
    -
    17683  }
    -
    17684  }
    -
    17685  else
    -
    17686  {
    -
    17687  return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset);
    -
    17688  }
    -
    17689 }
    -
    17690 
    -
    17691 VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData)
    -
    17692 {
    -
    17693  if(hAllocation->CanBecomeLost())
    -
    17694  {
    -
    17695  return VK_ERROR_MEMORY_MAP_FAILED;
    -
    17696  }
    -
    17697 
    -
    17698  switch(hAllocation->GetType())
    -
    17699  {
    -
    17700  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    -
    17701  {
    -
    17702  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
    -
    17703  char *pBytes = VMA_NULL;
    -
    17704  VkResult res = pBlock->Map(this, 1, (void**)&pBytes);
    -
    17705  if(res == VK_SUCCESS)
    -
    17706  {
    -
    17707  *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset();
    -
    17708  hAllocation->BlockAllocMap();
    -
    17709  }
    -
    17710  return res;
    -
    17711  }
    -
    17712  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    -
    17713  return hAllocation->DedicatedAllocMap(this, ppData);
    -
    17714  default:
    -
    17715  VMA_ASSERT(0);
    -
    17716  return VK_ERROR_MEMORY_MAP_FAILED;
    -
    17717  }
    -
    17718 }
    -
    17719 
    -
    17720 void VmaAllocator_T::Unmap(VmaAllocation hAllocation)
    -
    17721 {
    -
    17722  switch(hAllocation->GetType())
    -
    17723  {
    -
    17724  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    -
    17725  {
    -
    17726  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
    -
    17727  hAllocation->BlockAllocUnmap();
    -
    17728  pBlock->Unmap(this, 1);
    -
    17729  }
    -
    17730  break;
    -
    17731  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    -
    17732  hAllocation->DedicatedAllocUnmap(this);
    -
    17733  break;
    -
    17734  default:
    -
    17735  VMA_ASSERT(0);
    -
    17736  }
    -
    17737 }
    -
    17738 
    -
    17739 VkResult VmaAllocator_T::BindBufferMemory(
    -
    17740  VmaAllocation hAllocation,
    -
    17741  VkDeviceSize allocationLocalOffset,
    -
    17742  VkBuffer hBuffer,
    -
    17743  const void* pNext)
    -
    17744 {
    -
    17745  VkResult res = VK_SUCCESS;
    -
    17746  switch(hAllocation->GetType())
    -
    17747  {
    -
    17748  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    -
    17749  res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext);
    -
    17750  break;
    -
    17751  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    -
    17752  {
    -
    17753  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
    -
    17754  VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block. Is the allocation lost?");
    -
    17755  res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext);
    -
    17756  break;
    -
    17757  }
    -
    17758  default:
    -
    17759  VMA_ASSERT(0);
    -
    17760  }
    -
    17761  return res;
    -
    17762 }
    -
    17763 
    -
    17764 VkResult VmaAllocator_T::BindImageMemory(
    -
    17765  VmaAllocation hAllocation,
    -
    17766  VkDeviceSize allocationLocalOffset,
    -
    17767  VkImage hImage,
    -
    17768  const void* pNext)
    -
    17769 {
    -
    17770  VkResult res = VK_SUCCESS;
    -
    17771  switch(hAllocation->GetType())
    -
    17772  {
    -
    17773  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    -
    17774  res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext);
    -
    17775  break;
    -
    17776  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    -
    17777  {
    -
    17778  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
    -
    17779  VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block. Is the allocation lost?");
    -
    17780  res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext);
    -
    17781  break;
    -
    17782  }
    -
    17783  default:
    -
    17784  VMA_ASSERT(0);
    -
    17785  }
    -
    17786  return res;
    -
    17787 }
    -
    17788 
    -
    17789 VkResult VmaAllocator_T::FlushOrInvalidateAllocation(
    -
    17790  VmaAllocation hAllocation,
    -
    17791  VkDeviceSize offset, VkDeviceSize size,
    -
    17792  VMA_CACHE_OPERATION op)
    -
    17793 {
    -
    17794  VkResult res = VK_SUCCESS;
    -
    17795 
    -
    17796  VkMappedMemoryRange memRange = {};
    -
    17797  if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange))
    -
    17798  {
    -
    17799  switch(op)
    -
    17800  {
    -
    17801  case VMA_CACHE_FLUSH:
    -
    17802  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange);
    -
    17803  break;
    -
    17804  case VMA_CACHE_INVALIDATE:
    -
    17805  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange);
    -
    17806  break;
    -
    17807  default:
    -
    17808  VMA_ASSERT(0);
    -
    17809  }
    -
    17810  }
    -
    17811  // else: Just ignore this call.
    -
    17812  return res;
    -
    17813 }
    -
    17814 
    -
    17815 VkResult VmaAllocator_T::FlushOrInvalidateAllocations(
    -
    17816  uint32_t allocationCount,
    -
    17817  const VmaAllocation* allocations,
    -
    17818  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
    -
    17819  VMA_CACHE_OPERATION op)
    -
    17820 {
    -
    17821  typedef VmaStlAllocator<VkMappedMemoryRange> RangeAllocator;
    -
    17822  typedef VmaSmallVector<VkMappedMemoryRange, RangeAllocator, 16> RangeVector;
    -
    17823  RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks()));
    -
    17824 
    -
    17825  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    -
    17826  {
    -
    17827  const VmaAllocation alloc = allocations[allocIndex];
    -
    17828  const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0;
    -
    17829  const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE;
    -
    17830  VkMappedMemoryRange newRange;
    -
    17831  if(GetFlushOrInvalidateRange(alloc, offset, size, newRange))
    -
    17832  {
    -
    17833  ranges.push_back(newRange);
    -
    17834  }
    -
    17835  }
    -
    17836 
    -
    17837  VkResult res = VK_SUCCESS;
    -
    17838  if(!ranges.empty())
    -
    17839  {
    -
    17840  switch(op)
    -
    17841  {
    -
    17842  case VMA_CACHE_FLUSH:
    -
    17843  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
    -
    17844  break;
    -
    17845  case VMA_CACHE_INVALIDATE:
    -
    17846  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
    -
    17847  break;
    -
    17848  default:
    -
    17849  VMA_ASSERT(0);
    -
    17850  }
    -
    17851  }
    -
    17852  // else: Just ignore this call.
    -
    17853  return res;
    -
    17854 }
    -
    17855 
    -
    17856 void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
    -
    17857 {
    -
    17858  VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    -
    17859 
    -
    17860  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    -
    17861  {
    -
    17862  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    -
    17863  DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
    -
    17864  dedicatedAllocations.Remove(allocation);
    -
    17865  }
    -
    17866 
    -
    17867  VkDeviceMemory hMemory = allocation->GetMemory();
    -
    17868 
    -
    17869  /*
    -
    17870  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
    -
    17871  before vkFreeMemory.
    -
    17872 
    -
    17873  if(allocation->GetMappedData() != VMA_NULL)
    -
    17874  {
    -
    17875  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
    -
    17876  }
    -
    17877  */
    -
    17878 
    -
    17879  FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
    -
    17880 
    -
    17881  VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex);
    -
    17882 }
    +
    17620  else
    +
    17621  {
    +
    17622  m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize;
    +
    17623  }
    +
    17624 
    +
    17625  return res;
    +
    17626 }
    +
    17627 
    +
    17628 void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory)
    +
    17629 {
    +
    17630  // Informative callback.
    +
    17631  if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
    +
    17632  {
    +
    17633  (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData);
    +
    17634  }
    +
    17635 
    +
    17636  // VULKAN CALL vkFreeMemory.
    +
    17637  (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
    +
    17638 
    +
    17639  m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
    +
    17640 
    +
    17641  --m_DeviceMemoryCount;
    +
    17642 }
    +
    17643 
    +
    17644 VkResult VmaAllocator_T::BindVulkanBuffer(
    +
    17645  VkDeviceMemory memory,
    +
    17646  VkDeviceSize memoryOffset,
    +
    17647  VkBuffer buffer,
    +
    17648  const void* pNext)
    +
    17649 {
    +
    17650  if(pNext != VMA_NULL)
    +
    17651  {
    +
    17652 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
    +
    17653  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
    +
    17654  m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL)
    +
    17655  {
    +
    17656  VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR };
    +
    17657  bindBufferMemoryInfo.pNext = pNext;
    +
    17658  bindBufferMemoryInfo.buffer = buffer;
    +
    17659  bindBufferMemoryInfo.memory = memory;
    +
    17660  bindBufferMemoryInfo.memoryOffset = memoryOffset;
    +
    17661  return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
    +
    17662  }
    +
    17663  else
    +
    17664 #endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
    +
    17665  {
    +
    17666  return VK_ERROR_EXTENSION_NOT_PRESENT;
    +
    17667  }
    +
    17668  }
    +
    17669  else
    +
    17670  {
    +
    17671  return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset);
    +
    17672  }
    +
    17673 }
    +
    17674 
    +
    17675 VkResult VmaAllocator_T::BindVulkanImage(
    +
    17676  VkDeviceMemory memory,
    +
    17677  VkDeviceSize memoryOffset,
    +
    17678  VkImage image,
    +
    17679  const void* pNext)
    +
    17680 {
    +
    17681  if(pNext != VMA_NULL)
    +
    17682  {
    +
    17683 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
    +
    17684  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
    +
    17685  m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL)
    +
    17686  {
    +
    17687  VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR };
    +
    17688  bindBufferMemoryInfo.pNext = pNext;
    +
    17689  bindBufferMemoryInfo.image = image;
    +
    17690  bindBufferMemoryInfo.memory = memory;
    +
    17691  bindBufferMemoryInfo.memoryOffset = memoryOffset;
    +
    17692  return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
    +
    17693  }
    +
    17694  else
    +
    17695 #endif // #if VMA_BIND_MEMORY2
    +
    17696  {
    +
    17697  return VK_ERROR_EXTENSION_NOT_PRESENT;
    +
    17698  }
    +
    17699  }
    +
    17700  else
    +
    17701  {
    +
    17702  return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset);
    +
    17703  }
    +
    17704 }
    +
    17705 
    +
    17706 VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData)
    +
    17707 {
    +
    17708  if(hAllocation->CanBecomeLost())
    +
    17709  {
    +
    17710  return VK_ERROR_MEMORY_MAP_FAILED;
    +
    17711  }
    +
    17712 
    +
    17713  switch(hAllocation->GetType())
    +
    17714  {
    +
    17715  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    +
    17716  {
    +
    17717  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
    +
    17718  char *pBytes = VMA_NULL;
    +
    17719  VkResult res = pBlock->Map(this, 1, (void**)&pBytes);
    +
    17720  if(res == VK_SUCCESS)
    +
    17721  {
    +
    17722  *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset();
    +
    17723  hAllocation->BlockAllocMap();
    +
    17724  }
    +
    17725  return res;
    +
    17726  }
    +
    17727  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    +
    17728  return hAllocation->DedicatedAllocMap(this, ppData);
    +
    17729  default:
    +
    17730  VMA_ASSERT(0);
    +
    17731  return VK_ERROR_MEMORY_MAP_FAILED;
    +
    17732  }
    +
    17733 }
    +
    17734 
    +
    17735 void VmaAllocator_T::Unmap(VmaAllocation hAllocation)
    +
    17736 {
    +
    17737  switch(hAllocation->GetType())
    +
    17738  {
    +
    17739  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    +
    17740  {
    +
    17741  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
    +
    17742  hAllocation->BlockAllocUnmap();
    +
    17743  pBlock->Unmap(this, 1);
    +
    17744  }
    +
    17745  break;
    +
    17746  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    +
    17747  hAllocation->DedicatedAllocUnmap(this);
    +
    17748  break;
    +
    17749  default:
    +
    17750  VMA_ASSERT(0);
    +
    17751  }
    +
    17752 }
    +
    17753 
    +
    17754 VkResult VmaAllocator_T::BindBufferMemory(
    +
    17755  VmaAllocation hAllocation,
    +
    17756  VkDeviceSize allocationLocalOffset,
    +
    17757  VkBuffer hBuffer,
    +
    17758  const void* pNext)
    +
    17759 {
    +
    17760  VkResult res = VK_SUCCESS;
    +
    17761  switch(hAllocation->GetType())
    +
    17762  {
    +
    17763  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    +
    17764  res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext);
    +
    17765  break;
    +
    17766  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    +
    17767  {
    +
    17768  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
    +
    17769  VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block. Is the allocation lost?");
    +
    17770  res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext);
    +
    17771  break;
    +
    17772  }
    +
    17773  default:
    +
    17774  VMA_ASSERT(0);
    +
    17775  }
    +
    17776  return res;
    +
    17777 }
    +
    17778 
    +
    17779 VkResult VmaAllocator_T::BindImageMemory(
    +
    17780  VmaAllocation hAllocation,
    +
    17781  VkDeviceSize allocationLocalOffset,
    +
    17782  VkImage hImage,
    +
    17783  const void* pNext)
    +
    17784 {
    +
    17785  VkResult res = VK_SUCCESS;
    +
    17786  switch(hAllocation->GetType())
    +
    17787  {
    +
    17788  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    +
    17789  res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext);
    +
    17790  break;
    +
    17791  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    +
    17792  {
    +
    17793  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
    +
    17794  VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block. Is the allocation lost?");
    +
    17795  res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext);
    +
    17796  break;
    +
    17797  }
    +
    17798  default:
    +
    17799  VMA_ASSERT(0);
    +
    17800  }
    +
    17801  return res;
    +
    17802 }
    +
    17803 
    +
    17804 VkResult VmaAllocator_T::FlushOrInvalidateAllocation(
    +
    17805  VmaAllocation hAllocation,
    +
    17806  VkDeviceSize offset, VkDeviceSize size,
    +
    17807  VMA_CACHE_OPERATION op)
    +
    17808 {
    +
    17809  VkResult res = VK_SUCCESS;
    +
    17810 
    +
    17811  VkMappedMemoryRange memRange = {};
    +
    17812  if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange))
    +
    17813  {
    +
    17814  switch(op)
    +
    17815  {
    +
    17816  case VMA_CACHE_FLUSH:
    +
    17817  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange);
    +
    17818  break;
    +
    17819  case VMA_CACHE_INVALIDATE:
    +
    17820  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange);
    +
    17821  break;
    +
    17822  default:
    +
    17823  VMA_ASSERT(0);
    +
    17824  }
    +
    17825  }
    +
    17826  // else: Just ignore this call.
    +
    17827  return res;
    +
    17828 }
    +
    17829 
    +
    17830 VkResult VmaAllocator_T::FlushOrInvalidateAllocations(
    +
    17831  uint32_t allocationCount,
    +
    17832  const VmaAllocation* allocations,
    +
    17833  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
    +
    17834  VMA_CACHE_OPERATION op)
    +
    17835 {
    +
    17836  typedef VmaStlAllocator<VkMappedMemoryRange> RangeAllocator;
    +
    17837  typedef VmaSmallVector<VkMappedMemoryRange, RangeAllocator, 16> RangeVector;
    +
    17838  RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks()));
    +
    17839 
    +
    17840  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    +
    17841  {
    +
    17842  const VmaAllocation alloc = allocations[allocIndex];
    +
    17843  const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0;
    +
    17844  const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE;
    +
    17845  VkMappedMemoryRange newRange;
    +
    17846  if(GetFlushOrInvalidateRange(alloc, offset, size, newRange))
    +
    17847  {
    +
    17848  ranges.push_back(newRange);
    +
    17849  }
    +
    17850  }
    +
    17851 
    +
    17852  VkResult res = VK_SUCCESS;
    +
    17853  if(!ranges.empty())
    +
    17854  {
    +
    17855  switch(op)
    +
    17856  {
    +
    17857  case VMA_CACHE_FLUSH:
    +
    17858  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
    +
    17859  break;
    +
    17860  case VMA_CACHE_INVALIDATE:
    +
    17861  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
    +
    17862  break;
    +
    17863  default:
    +
    17864  VMA_ASSERT(0);
    +
    17865  }
    +
    17866  }
    +
    17867  // else: Just ignore this call.
    +
    17868  return res;
    +
    17869 }
    +
    17870 
    +
    17871 void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
    +
    17872 {
    +
    17873  VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
    +
    17874 
    +
    17875  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    +
    17876  {
    +
    17877  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    +
    17878  DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
    +
    17879  dedicatedAllocations.Remove(allocation);
    +
    17880  }
    +
    17881 
    +
    17882  VkDeviceMemory hMemory = allocation->GetMemory();
    17883 
    -
    17884 uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const
    -
    17885 {
    -
    17886  VkBufferCreateInfo dummyBufCreateInfo;
    -
    17887  VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo);
    -
    17888 
    -
    17889  uint32_t memoryTypeBits = 0;
    -
    17890 
    -
    17891  // Create buffer.
    -
    17892  VkBuffer buf = VK_NULL_HANDLE;
    -
    17893  VkResult res = (*GetVulkanFunctions().vkCreateBuffer)(
    -
    17894  m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf);
    -
    17895  if(res == VK_SUCCESS)
    -
    17896  {
    -
    17897  // Query for supported memory types.
    -
    17898  VkMemoryRequirements memReq;
    -
    17899  (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq);
    -
    17900  memoryTypeBits = memReq.memoryTypeBits;
    -
    17901 
    -
    17902  // Destroy buffer.
    -
    17903  (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks());
    -
    17904  }
    +
    17884  /*
    +
    17885  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
    +
    17886  before vkFreeMemory.
    +
    17887 
    +
    17888  if(allocation->GetMappedData() != VMA_NULL)
    +
    17889  {
    +
    17890  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
    +
    17891  }
    +
    17892  */
    +
    17893 
    +
    17894  FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
    +
    17895 
    +
    17896  VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex);
    +
    17897 }
    +
    17898 
    +
    17899 uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const
    +
    17900 {
    +
    17901  VkBufferCreateInfo dummyBufCreateInfo;
    +
    17902  VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo);
    +
    17903 
    +
    17904  uint32_t memoryTypeBits = 0;
    17905 
    -
    17906  return memoryTypeBits;
    -
    17907 }
    -
    17908 
    -
    17909 uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const
    -
    17910 {
    -
    17911  // Make sure memory information is already fetched.
    -
    17912  VMA_ASSERT(GetMemoryTypeCount() > 0);
    -
    17913 
    -
    17914  uint32_t memoryTypeBits = UINT32_MAX;
    -
    17915 
    -
    17916  if(!m_UseAmdDeviceCoherentMemory)
    -
    17917  {
    -
    17918  // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD.
    -
    17919  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    17920  {
    -
    17921  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
    -
    17922  {
    -
    17923  memoryTypeBits &= ~(1u << memTypeIndex);
    -
    17924  }
    -
    17925  }
    -
    17926  }
    -
    17927 
    -
    17928  return memoryTypeBits;
    -
    17929 }
    +
    17906  // Create buffer.
    +
    17907  VkBuffer buf = VK_NULL_HANDLE;
    +
    17908  VkResult res = (*GetVulkanFunctions().vkCreateBuffer)(
    +
    17909  m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf);
    +
    17910  if(res == VK_SUCCESS)
    +
    17911  {
    +
    17912  // Query for supported memory types.
    +
    17913  VkMemoryRequirements memReq;
    +
    17914  (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq);
    +
    17915  memoryTypeBits = memReq.memoryTypeBits;
    +
    17916 
    +
    17917  // Destroy buffer.
    +
    17918  (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks());
    +
    17919  }
    +
    17920 
    +
    17921  return memoryTypeBits;
    +
    17922 }
    +
    17923 
    +
    17924 uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const
    +
    17925 {
    +
    17926  // Make sure memory information is already fetched.
    +
    17927  VMA_ASSERT(GetMemoryTypeCount() > 0);
    +
    17928 
    +
    17929  uint32_t memoryTypeBits = UINT32_MAX;
    17930 
    -
    17931 bool VmaAllocator_T::GetFlushOrInvalidateRange(
    -
    17932  VmaAllocation allocation,
    -
    17933  VkDeviceSize offset, VkDeviceSize size,
    -
    17934  VkMappedMemoryRange& outRange) const
    -
    17935 {
    -
    17936  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    -
    17937  if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex))
    -
    17938  {
    -
    17939  const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
    -
    17940  const VkDeviceSize allocationSize = allocation->GetSize();
    -
    17941  VMA_ASSERT(offset <= allocationSize);
    +
    17931  if(!m_UseAmdDeviceCoherentMemory)
    +
    17932  {
    +
    17933  // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD.
    +
    17934  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    17935  {
    +
    17936  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
    +
    17937  {
    +
    17938  memoryTypeBits &= ~(1u << memTypeIndex);
    +
    17939  }
    +
    17940  }
    +
    17941  }
    17942 
    -
    17943  outRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
    -
    17944  outRange.pNext = VMA_NULL;
    -
    17945  outRange.memory = allocation->GetMemory();
    -
    17946 
    -
    17947  switch(allocation->GetType())
    -
    17948  {
    -
    17949  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    -
    17950  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
    -
    17951  if(size == VK_WHOLE_SIZE)
    -
    17952  {
    -
    17953  outRange.size = allocationSize - outRange.offset;
    -
    17954  }
    -
    17955  else
    -
    17956  {
    -
    17957  VMA_ASSERT(offset + size <= allocationSize);
    -
    17958  outRange.size = VMA_MIN(
    -
    17959  VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize),
    -
    17960  allocationSize - outRange.offset);
    -
    17961  }
    -
    17962  break;
    -
    17963  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    -
    17964  {
    -
    17965  // 1. Still within this allocation.
    -
    17966  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
    -
    17967  if(size == VK_WHOLE_SIZE)
    -
    17968  {
    -
    17969  size = allocationSize - offset;
    -
    17970  }
    -
    17971  else
    -
    17972  {
    -
    17973  VMA_ASSERT(offset + size <= allocationSize);
    -
    17974  }
    -
    17975  outRange.size = VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize);
    -
    17976 
    -
    17977  // 2. Adjust to whole block.
    -
    17978  const VkDeviceSize allocationOffset = allocation->GetOffset();
    -
    17979  VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0);
    -
    17980  const VkDeviceSize blockSize = allocation->GetBlock()->m_pMetadata->GetSize();
    -
    17981  outRange.offset += allocationOffset;
    -
    17982  outRange.size = VMA_MIN(outRange.size, blockSize - outRange.offset);
    -
    17983 
    -
    17984  break;
    -
    17985  }
    -
    17986  default:
    -
    17987  VMA_ASSERT(0);
    -
    17988  }
    -
    17989  return true;
    -
    17990  }
    -
    17991  return false;
    -
    17992 }
    -
    17993 
    -
    17994 #if VMA_MEMORY_BUDGET
    -
    17995 
    -
    17996 void VmaAllocator_T::UpdateVulkanBudget()
    -
    17997 {
    -
    17998  VMA_ASSERT(m_UseExtMemoryBudget);
    -
    17999 
    -
    18000  VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR };
    -
    18001 
    -
    18002  VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT };
    -
    18003  VmaPnextChainPushFront(&memProps, &budgetProps);
    -
    18004 
    -
    18005  GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps);
    -
    18006 
    -
    18007  {
    -
    18008  VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex);
    -
    18009 
    -
    18010  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
    -
    18011  {
    -
    18012  m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex];
    -
    18013  m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex];
    -
    18014  m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load();
    -
    18015 
    -
    18016  // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size.
    -
    18017  if(m_Budget.m_VulkanBudget[heapIndex] == 0)
    -
    18018  {
    -
    18019  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
    -
    18020  }
    -
    18021  else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size)
    -
    18022  {
    -
    18023  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size;
    -
    18024  }
    -
    18025  if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0)
    -
    18026  {
    -
    18027  m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
    -
    18028  }
    -
    18029  }
    -
    18030  m_Budget.m_OperationsSinceBudgetFetch = 0;
    -
    18031  }
    -
    18032 }
    -
    18033 
    -
    18034 #endif // #if VMA_MEMORY_BUDGET
    -
    18035 
    -
    18036 void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern)
    -
    18037 {
    -
    18038  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS &&
    -
    18039  !hAllocation->CanBecomeLost() &&
    -
    18040  (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    -
    18041  {
    -
    18042  void* pData = VMA_NULL;
    -
    18043  VkResult res = Map(hAllocation, &pData);
    -
    18044  if(res == VK_SUCCESS)
    -
    18045  {
    -
    18046  memset(pData, (int)pattern, (size_t)hAllocation->GetSize());
    -
    18047  FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH);
    -
    18048  Unmap(hAllocation);
    -
    18049  }
    -
    18050  else
    -
    18051  {
    -
    18052  VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation.");
    -
    18053  }
    -
    18054  }
    -
    18055 }
    -
    18056 
    -
    18057 uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits()
    -
    18058 {
    -
    18059  uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load();
    -
    18060  if(memoryTypeBits == UINT32_MAX)
    -
    18061  {
    -
    18062  memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits();
    -
    18063  m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits);
    -
    18064  }
    -
    18065  return memoryTypeBits;
    -
    18066 }
    -
    18067 
    -
    18068 #if VMA_STATS_STRING_ENABLED
    -
    18069 
    -
    18070 void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
    -
    18071 {
    -
    18072  bool dedicatedAllocationsStarted = false;
    -
    18073  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    18074  {
    -
    18075  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    -
    18076  DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
    -
    18077  if(!dedicatedAllocList.IsEmpty())
    -
    18078  {
    -
    18079  if(dedicatedAllocationsStarted == false)
    -
    18080  {
    -
    18081  dedicatedAllocationsStarted = true;
    -
    18082  json.WriteString("DedicatedAllocations");
    -
    18083  json.BeginObject();
    -
    18084  }
    -
    18085 
    -
    18086  json.BeginString("Type ");
    -
    18087  json.ContinueString(memTypeIndex);
    -
    18088  json.EndString();
    -
    18089 
    -
    18090  json.BeginArray();
    -
    18091 
    -
    18092  for(VmaAllocation alloc = dedicatedAllocList.Front();
    -
    18093  alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
    -
    18094  {
    -
    18095  json.BeginObject(true);
    -
    18096  alloc->PrintParameters(json);
    -
    18097  json.EndObject();
    -
    18098  }
    -
    18099 
    -
    18100  json.EndArray();
    -
    18101  }
    -
    18102  }
    -
    18103  if(dedicatedAllocationsStarted)
    -
    18104  {
    -
    18105  json.EndObject();
    -
    18106  }
    -
    18107 
    -
    18108  {
    -
    18109  bool allocationsStarted = false;
    -
    18110  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    -
    18111  {
    -
    18112  if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false)
    -
    18113  {
    -
    18114  if(allocationsStarted == false)
    -
    18115  {
    -
    18116  allocationsStarted = true;
    -
    18117  json.WriteString("DefaultPools");
    -
    18118  json.BeginObject();
    -
    18119  }
    -
    18120 
    -
    18121  json.BeginString("Type ");
    -
    18122  json.ContinueString(memTypeIndex);
    -
    18123  json.EndString();
    -
    18124 
    -
    18125  m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json);
    -
    18126  }
    -
    18127  }
    -
    18128  if(allocationsStarted)
    -
    18129  {
    -
    18130  json.EndObject();
    -
    18131  }
    -
    18132  }
    -
    18133 
    -
    18134  // Custom pools
    -
    18135  {
    -
    18136  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
    -
    18137  if(!m_Pools.IsEmpty())
    -
    18138  {
    -
    18139  json.WriteString("Pools");
    -
    18140  json.BeginObject();
    -
    18141  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
    -
    18142  {
    -
    18143  json.BeginString();
    -
    18144  json.ContinueString(pool->GetId());
    -
    18145  json.EndString();
    -
    18146 
    -
    18147  pool->m_BlockVector.PrintDetailedMap(json);
    -
    18148  }
    -
    18149  json.EndObject();
    -
    18150  }
    -
    18151  }
    -
    18152 }
    -
    18153 
    -
    18154 #endif // #if VMA_STATS_STRING_ENABLED
    -
    18155 
    -
    18157 // Public interface
    -
    18158 
    -
    18159 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator(
    -
    18160  const VmaAllocatorCreateInfo* pCreateInfo,
    -
    18161  VmaAllocator* pAllocator)
    -
    18162 {
    -
    18163  VMA_ASSERT(pCreateInfo && pAllocator);
    -
    18164  VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 ||
    -
    18165  (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 2));
    -
    18166  VMA_DEBUG_LOG("vmaCreateAllocator");
    -
    18167  *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
    -
    18168  return (*pAllocator)->Init(pCreateInfo);
    -
    18169 }
    +
    17943  return memoryTypeBits;
    +
    17944 }
    +
    17945 
    +
    17946 bool VmaAllocator_T::GetFlushOrInvalidateRange(
    +
    17947  VmaAllocation allocation,
    +
    17948  VkDeviceSize offset, VkDeviceSize size,
    +
    17949  VkMappedMemoryRange& outRange) const
    +
    17950 {
    +
    17951  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    +
    17952  if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex))
    +
    17953  {
    +
    17954  const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
    +
    17955  const VkDeviceSize allocationSize = allocation->GetSize();
    +
    17956  VMA_ASSERT(offset <= allocationSize);
    +
    17957 
    +
    17958  outRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
    +
    17959  outRange.pNext = VMA_NULL;
    +
    17960  outRange.memory = allocation->GetMemory();
    +
    17961 
    +
    17962  switch(allocation->GetType())
    +
    17963  {
    +
    17964  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
    +
    17965  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
    +
    17966  if(size == VK_WHOLE_SIZE)
    +
    17967  {
    +
    17968  outRange.size = allocationSize - outRange.offset;
    +
    17969  }
    +
    17970  else
    +
    17971  {
    +
    17972  VMA_ASSERT(offset + size <= allocationSize);
    +
    17973  outRange.size = VMA_MIN(
    +
    17974  VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize),
    +
    17975  allocationSize - outRange.offset);
    +
    17976  }
    +
    17977  break;
    +
    17978  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
    +
    17979  {
    +
    17980  // 1. Still within this allocation.
    +
    17981  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
    +
    17982  if(size == VK_WHOLE_SIZE)
    +
    17983  {
    +
    17984  size = allocationSize - offset;
    +
    17985  }
    +
    17986  else
    +
    17987  {
    +
    17988  VMA_ASSERT(offset + size <= allocationSize);
    +
    17989  }
    +
    17990  outRange.size = VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize);
    +
    17991 
    +
    17992  // 2. Adjust to whole block.
    +
    17993  const VkDeviceSize allocationOffset = allocation->GetOffset();
    +
    17994  VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0);
    +
    17995  const VkDeviceSize blockSize = allocation->GetBlock()->m_pMetadata->GetSize();
    +
    17996  outRange.offset += allocationOffset;
    +
    17997  outRange.size = VMA_MIN(outRange.size, blockSize - outRange.offset);
    +
    17998 
    +
    17999  break;
    +
    18000  }
    +
    18001  default:
    +
    18002  VMA_ASSERT(0);
    +
    18003  }
    +
    18004  return true;
    +
    18005  }
    +
    18006  return false;
    +
    18007 }
    +
    18008 
    +
    18009 #if VMA_MEMORY_BUDGET
    +
    18010 
    +
    18011 void VmaAllocator_T::UpdateVulkanBudget()
    +
    18012 {
    +
    18013  VMA_ASSERT(m_UseExtMemoryBudget);
    +
    18014 
    +
    18015  VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR };
    +
    18016 
    +
    18017  VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT };
    +
    18018  VmaPnextChainPushFront(&memProps, &budgetProps);
    +
    18019 
    +
    18020  GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps);
    +
    18021 
    +
    18022  {
    +
    18023  VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex);
    +
    18024 
    +
    18025  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
    +
    18026  {
    +
    18027  m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex];
    +
    18028  m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex];
    +
    18029  m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load();
    +
    18030 
    +
    18031  // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size.
    +
    18032  if(m_Budget.m_VulkanBudget[heapIndex] == 0)
    +
    18033  {
    +
    18034  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
    +
    18035  }
    +
    18036  else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size)
    +
    18037  {
    +
    18038  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size;
    +
    18039  }
    +
    18040  if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0)
    +
    18041  {
    +
    18042  m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
    +
    18043  }
    +
    18044  }
    +
    18045  m_Budget.m_OperationsSinceBudgetFetch = 0;
    +
    18046  }
    +
    18047 }
    +
    18048 
    +
    18049 #endif // #if VMA_MEMORY_BUDGET
    +
    18050 
    +
    18051 void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern)
    +
    18052 {
    +
    18053  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS &&
    +
    18054  !hAllocation->CanBecomeLost() &&
    +
    18055  (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    +
    18056  {
    +
    18057  void* pData = VMA_NULL;
    +
    18058  VkResult res = Map(hAllocation, &pData);
    +
    18059  if(res == VK_SUCCESS)
    +
    18060  {
    +
    18061  memset(pData, (int)pattern, (size_t)hAllocation->GetSize());
    +
    18062  FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH);
    +
    18063  Unmap(hAllocation);
    +
    18064  }
    +
    18065  else
    +
    18066  {
    +
    18067  VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation.");
    +
    18068  }
    +
    18069  }
    +
    18070 }
    +
    18071 
    +
    18072 uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits()
    +
    18073 {
    +
    18074  uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load();
    +
    18075  if(memoryTypeBits == UINT32_MAX)
    +
    18076  {
    +
    18077  memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits();
    +
    18078  m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits);
    +
    18079  }
    +
    18080  return memoryTypeBits;
    +
    18081 }
    +
    18082 
    +
    18083 #if VMA_STATS_STRING_ENABLED
    +
    18084 
    +
    18085 void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
    +
    18086 {
    +
    18087  bool dedicatedAllocationsStarted = false;
    +
    18088  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    18089  {
    +
    18090  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
    +
    18091  DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
    +
    18092  if(!dedicatedAllocList.IsEmpty())
    +
    18093  {
    +
    18094  if(dedicatedAllocationsStarted == false)
    +
    18095  {
    +
    18096  dedicatedAllocationsStarted = true;
    +
    18097  json.WriteString("DedicatedAllocations");
    +
    18098  json.BeginObject();
    +
    18099  }
    +
    18100 
    +
    18101  json.BeginString("Type ");
    +
    18102  json.ContinueString(memTypeIndex);
    +
    18103  json.EndString();
    +
    18104 
    +
    18105  json.BeginArray();
    +
    18106 
    +
    18107  for(VmaAllocation alloc = dedicatedAllocList.Front();
    +
    18108  alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
    +
    18109  {
    +
    18110  json.BeginObject(true);
    +
    18111  alloc->PrintParameters(json);
    +
    18112  json.EndObject();
    +
    18113  }
    +
    18114 
    +
    18115  json.EndArray();
    +
    18116  }
    +
    18117  }
    +
    18118  if(dedicatedAllocationsStarted)
    +
    18119  {
    +
    18120  json.EndObject();
    +
    18121  }
    +
    18122 
    +
    18123  {
    +
    18124  bool allocationsStarted = false;
    +
    18125  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    +
    18126  {
    +
    18127  if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false)
    +
    18128  {
    +
    18129  if(allocationsStarted == false)
    +
    18130  {
    +
    18131  allocationsStarted = true;
    +
    18132  json.WriteString("DefaultPools");
    +
    18133  json.BeginObject();
    +
    18134  }
    +
    18135 
    +
    18136  json.BeginString("Type ");
    +
    18137  json.ContinueString(memTypeIndex);
    +
    18138  json.EndString();
    +
    18139 
    +
    18140  m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json);
    +
    18141  }
    +
    18142  }
    +
    18143  if(allocationsStarted)
    +
    18144  {
    +
    18145  json.EndObject();
    +
    18146  }
    +
    18147  }
    +
    18148 
    +
    18149  // Custom pools
    +
    18150  {
    +
    18151  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
    +
    18152  if(!m_Pools.IsEmpty())
    +
    18153  {
    +
    18154  json.WriteString("Pools");
    +
    18155  json.BeginObject();
    +
    18156  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
    +
    18157  {
    +
    18158  json.BeginString();
    +
    18159  json.ContinueString(pool->GetId());
    +
    18160  json.EndString();
    +
    18161 
    +
    18162  pool->m_BlockVector.PrintDetailedMap(json);
    +
    18163  }
    +
    18164  json.EndObject();
    +
    18165  }
    +
    18166  }
    +
    18167 }
    +
    18168 
    +
    18169 #endif // #if VMA_STATS_STRING_ENABLED
    18170 
    -
    18171 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator(
    -
    18172  VmaAllocator allocator)
    -
    18173 {
    -
    18174  if(allocator != VK_NULL_HANDLE)
    -
    18175  {
    -
    18176  VMA_DEBUG_LOG("vmaDestroyAllocator");
    -
    18177  VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
    -
    18178  vma_delete(&allocationCallbacks, allocator);
    -
    18179  }
    -
    18180 }
    -
    18181 
    -
    18182 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo)
    -
    18183 {
    -
    18184  VMA_ASSERT(allocator && pAllocatorInfo);
    -
    18185  pAllocatorInfo->instance = allocator->m_hInstance;
    -
    18186  pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice();
    -
    18187  pAllocatorInfo->device = allocator->m_hDevice;
    -
    18188 }
    -
    18189 
    -
    18190 VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties(
    -
    18191  VmaAllocator allocator,
    -
    18192  const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
    -
    18193 {
    -
    18194  VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
    -
    18195  *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
    -
    18196 }
    -
    18197 
    -
    18198 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties(
    -
    18199  VmaAllocator allocator,
    -
    18200  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
    -
    18201 {
    -
    18202  VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
    -
    18203  *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
    -
    18204 }
    -
    18205 
    -
    18206 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties(
    -
    18207  VmaAllocator allocator,
    -
    18208  uint32_t memoryTypeIndex,
    -
    18209  VkMemoryPropertyFlags* pFlags)
    -
    18210 {
    -
    18211  VMA_ASSERT(allocator && pFlags);
    -
    18212  VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
    -
    18213  *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
    -
    18214 }
    -
    18215 
    -
    18216 VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex(
    -
    18217  VmaAllocator allocator,
    -
    18218  uint32_t frameIndex)
    -
    18219 {
    -
    18220  VMA_ASSERT(allocator);
    -
    18221  VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST);
    -
    18222 
    -
    18223  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18224 
    -
    18225  allocator->SetCurrentFrameIndex(frameIndex);
    -
    18226 }
    -
    18227 
    -
    18228 VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats(
    -
    18229  VmaAllocator allocator,
    -
    18230  VmaStats* pStats)
    -
    18231 {
    -
    18232  VMA_ASSERT(allocator && pStats);
    -
    18233  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18234  allocator->CalculateStats(pStats);
    -
    18235 }
    -
    18236 
    -
    18237 VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget(
    -
    18238  VmaAllocator allocator,
    -
    18239  VmaBudget* pBudget)
    -
    18240 {
    -
    18241  VMA_ASSERT(allocator && pBudget);
    -
    18242  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18243  allocator->GetBudget(pBudget, 0, allocator->GetMemoryHeapCount());
    -
    18244 }
    -
    18245 
    -
    18246 #if VMA_STATS_STRING_ENABLED
    -
    18247 
    -
    18248 VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString(
    -
    18249  VmaAllocator allocator,
    -
    18250  char** ppStatsString,
    -
    18251  VkBool32 detailedMap)
    -
    18252 {
    -
    18253  VMA_ASSERT(allocator && ppStatsString);
    -
    18254  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18255 
    -
    18256  VmaStringBuilder sb(allocator);
    -
    18257  {
    -
    18258  VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
    -
    18259  json.BeginObject();
    +
    18172 // Public interface
    +
    18173 
    +
    18174 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator(
    +
    18175  const VmaAllocatorCreateInfo* pCreateInfo,
    +
    18176  VmaAllocator* pAllocator)
    +
    18177 {
    +
    18178  VMA_ASSERT(pCreateInfo && pAllocator);
    +
    18179  VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 ||
    +
    18180  (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 2));
    +
    18181  VMA_DEBUG_LOG("vmaCreateAllocator");
    +
    18182  *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
    +
    18183  return (*pAllocator)->Init(pCreateInfo);
    +
    18184 }
    +
    18185 
    +
    18186 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator(
    +
    18187  VmaAllocator allocator)
    +
    18188 {
    +
    18189  if(allocator != VK_NULL_HANDLE)
    +
    18190  {
    +
    18191  VMA_DEBUG_LOG("vmaDestroyAllocator");
    +
    18192  VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
    +
    18193  vma_delete(&allocationCallbacks, allocator);
    +
    18194  }
    +
    18195 }
    +
    18196 
    +
    18197 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo)
    +
    18198 {
    +
    18199  VMA_ASSERT(allocator && pAllocatorInfo);
    +
    18200  pAllocatorInfo->instance = allocator->m_hInstance;
    +
    18201  pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice();
    +
    18202  pAllocatorInfo->device = allocator->m_hDevice;
    +
    18203 }
    +
    18204 
    +
    18205 VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties(
    +
    18206  VmaAllocator allocator,
    +
    18207  const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
    +
    18208 {
    +
    18209  VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
    +
    18210  *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
    +
    18211 }
    +
    18212 
    +
    18213 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties(
    +
    18214  VmaAllocator allocator,
    +
    18215  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
    +
    18216 {
    +
    18217  VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
    +
    18218  *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
    +
    18219 }
    +
    18220 
    +
    18221 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties(
    +
    18222  VmaAllocator allocator,
    +
    18223  uint32_t memoryTypeIndex,
    +
    18224  VkMemoryPropertyFlags* pFlags)
    +
    18225 {
    +
    18226  VMA_ASSERT(allocator && pFlags);
    +
    18227  VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
    +
    18228  *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
    +
    18229 }
    +
    18230 
    +
    18231 VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex(
    +
    18232  VmaAllocator allocator,
    +
    18233  uint32_t frameIndex)
    +
    18234 {
    +
    18235  VMA_ASSERT(allocator);
    +
    18236  VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST);
    +
    18237 
    +
    18238  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18239 
    +
    18240  allocator->SetCurrentFrameIndex(frameIndex);
    +
    18241 }
    +
    18242 
    +
    18243 VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats(
    +
    18244  VmaAllocator allocator,
    +
    18245  VmaStats* pStats)
    +
    18246 {
    +
    18247  VMA_ASSERT(allocator && pStats);
    +
    18248  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18249  allocator->CalculateStats(pStats);
    +
    18250 }
    +
    18251 
    +
    18252 VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget(
    +
    18253  VmaAllocator allocator,
    +
    18254  VmaBudget* pBudget)
    +
    18255 {
    +
    18256  VMA_ASSERT(allocator && pBudget);
    +
    18257  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18258  allocator->GetBudget(pBudget, 0, allocator->GetMemoryHeapCount());
    +
    18259 }
    18260 
    -
    18261  VmaBudget budget[VK_MAX_MEMORY_HEAPS];
    -
    18262  allocator->GetBudget(budget, 0, allocator->GetMemoryHeapCount());
    -
    18263 
    -
    18264  VmaStats stats;
    -
    18265  allocator->CalculateStats(&stats);
    -
    18266 
    -
    18267  json.WriteString("Total");
    -
    18268  VmaPrintStatInfo(json, stats.total);
    -
    18269 
    -
    18270  for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
    -
    18271  {
    -
    18272  json.BeginString("Heap ");
    -
    18273  json.ContinueString(heapIndex);
    -
    18274  json.EndString();
    -
    18275  json.BeginObject();
    -
    18276 
    -
    18277  json.WriteString("Size");
    -
    18278  json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
    -
    18279 
    -
    18280  json.WriteString("Flags");
    -
    18281  json.BeginArray(true);
    -
    18282  if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
    -
    18283  {
    -
    18284  json.WriteString("DEVICE_LOCAL");
    -
    18285  }
    -
    18286  json.EndArray();
    -
    18287 
    -
    18288  json.WriteString("Budget");
    -
    18289  json.BeginObject();
    -
    18290  {
    -
    18291  json.WriteString("BlockBytes");
    -
    18292  json.WriteNumber(budget[heapIndex].blockBytes);
    -
    18293  json.WriteString("AllocationBytes");
    -
    18294  json.WriteNumber(budget[heapIndex].allocationBytes);
    -
    18295  json.WriteString("Usage");
    -
    18296  json.WriteNumber(budget[heapIndex].usage);
    -
    18297  json.WriteString("Budget");
    -
    18298  json.WriteNumber(budget[heapIndex].budget);
    -
    18299  }
    -
    18300  json.EndObject();
    -
    18301 
    -
    18302  if(stats.memoryHeap[heapIndex].blockCount > 0)
    -
    18303  {
    -
    18304  json.WriteString("Stats");
    -
    18305  VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]);
    -
    18306  }
    -
    18307 
    -
    18308  for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
    -
    18309  {
    -
    18310  if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex)
    -
    18311  {
    -
    18312  json.BeginString("Type ");
    -
    18313  json.ContinueString(typeIndex);
    -
    18314  json.EndString();
    -
    18315 
    -
    18316  json.BeginObject();
    -
    18317 
    -
    18318  json.WriteString("Flags");
    -
    18319  json.BeginArray(true);
    -
    18320  VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
    -
    18321  if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
    -
    18322  {
    -
    18323  json.WriteString("DEVICE_LOCAL");
    -
    18324  }
    -
    18325  if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    -
    18326  {
    -
    18327  json.WriteString("HOST_VISIBLE");
    -
    18328  }
    -
    18329  if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
    -
    18330  {
    -
    18331  json.WriteString("HOST_COHERENT");
    -
    18332  }
    -
    18333  if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
    -
    18334  {
    -
    18335  json.WriteString("HOST_CACHED");
    -
    18336  }
    -
    18337  if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
    -
    18338  {
    -
    18339  json.WriteString("LAZILY_ALLOCATED");
    -
    18340  }
    -
    18341 #if VMA_VULKAN_VERSION >= 1001000
    -
    18342  if((flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0)
    -
    18343  {
    -
    18344  json.WriteString("PROTECTED");
    -
    18345  }
    -
    18346 #endif // #if VMA_VULKAN_VERSION >= 1001000
    -
    18347 #if VK_AMD_device_coherent_memory
    -
    18348  if((flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
    +
    18261 #if VMA_STATS_STRING_ENABLED
    +
    18262 
    +
    18263 VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString(
    +
    18264  VmaAllocator allocator,
    +
    18265  char** ppStatsString,
    +
    18266  VkBool32 detailedMap)
    +
    18267 {
    +
    18268  VMA_ASSERT(allocator && ppStatsString);
    +
    18269  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18270 
    +
    18271  VmaStringBuilder sb(allocator);
    +
    18272  {
    +
    18273  VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
    +
    18274  json.BeginObject();
    +
    18275 
    +
    18276  VmaBudget budget[VK_MAX_MEMORY_HEAPS];
    +
    18277  allocator->GetBudget(budget, 0, allocator->GetMemoryHeapCount());
    +
    18278 
    +
    18279  VmaStats stats;
    +
    18280  allocator->CalculateStats(&stats);
    +
    18281 
    +
    18282  json.WriteString("Total");
    +
    18283  VmaPrintStatInfo(json, stats.total);
    +
    18284 
    +
    18285  for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
    +
    18286  {
    +
    18287  json.BeginString("Heap ");
    +
    18288  json.ContinueString(heapIndex);
    +
    18289  json.EndString();
    +
    18290  json.BeginObject();
    +
    18291 
    +
    18292  json.WriteString("Size");
    +
    18293  json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
    +
    18294 
    +
    18295  json.WriteString("Flags");
    +
    18296  json.BeginArray(true);
    +
    18297  if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
    +
    18298  {
    +
    18299  json.WriteString("DEVICE_LOCAL");
    +
    18300  }
    +
    18301  json.EndArray();
    +
    18302 
    +
    18303  json.WriteString("Budget");
    +
    18304  json.BeginObject();
    +
    18305  {
    +
    18306  json.WriteString("BlockBytes");
    +
    18307  json.WriteNumber(budget[heapIndex].blockBytes);
    +
    18308  json.WriteString("AllocationBytes");
    +
    18309  json.WriteNumber(budget[heapIndex].allocationBytes);
    +
    18310  json.WriteString("Usage");
    +
    18311  json.WriteNumber(budget[heapIndex].usage);
    +
    18312  json.WriteString("Budget");
    +
    18313  json.WriteNumber(budget[heapIndex].budget);
    +
    18314  }
    +
    18315  json.EndObject();
    +
    18316 
    +
    18317  if(stats.memoryHeap[heapIndex].blockCount > 0)
    +
    18318  {
    +
    18319  json.WriteString("Stats");
    +
    18320  VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]);
    +
    18321  }
    +
    18322 
    +
    18323  for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
    +
    18324  {
    +
    18325  if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex)
    +
    18326  {
    +
    18327  json.BeginString("Type ");
    +
    18328  json.ContinueString(typeIndex);
    +
    18329  json.EndString();
    +
    18330 
    +
    18331  json.BeginObject();
    +
    18332 
    +
    18333  json.WriteString("Flags");
    +
    18334  json.BeginArray(true);
    +
    18335  VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
    +
    18336  if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
    +
    18337  {
    +
    18338  json.WriteString("DEVICE_LOCAL");
    +
    18339  }
    +
    18340  if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    +
    18341  {
    +
    18342  json.WriteString("HOST_VISIBLE");
    +
    18343  }
    +
    18344  if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
    +
    18345  {
    +
    18346  json.WriteString("HOST_COHERENT");
    +
    18347  }
    +
    18348  if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
    18349  {
    -
    18350  json.WriteString("DEVICE_COHERENT");
    +
    18350  json.WriteString("HOST_CACHED");
    18351  }
    -
    18352  if((flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) != 0)
    +
    18352  if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
    18353  {
    -
    18354  json.WriteString("DEVICE_UNCACHED");
    +
    18354  json.WriteString("LAZILY_ALLOCATED");
    18355  }
    -
    18356 #endif // #if VK_AMD_device_coherent_memory
    -
    18357  json.EndArray();
    -
    18358 
    -
    18359  if(stats.memoryType[typeIndex].blockCount > 0)
    -
    18360  {
    -
    18361  json.WriteString("Stats");
    -
    18362  VmaPrintStatInfo(json, stats.memoryType[typeIndex]);
    -
    18363  }
    -
    18364 
    -
    18365  json.EndObject();
    -
    18366  }
    -
    18367  }
    -
    18368 
    -
    18369  json.EndObject();
    -
    18370  }
    -
    18371  if(detailedMap == VK_TRUE)
    -
    18372  {
    -
    18373  allocator->PrintDetailedMap(json);
    -
    18374  }
    -
    18375 
    -
    18376  json.EndObject();
    -
    18377  }
    -
    18378 
    -
    18379  const size_t len = sb.GetLength();
    -
    18380  char* const pChars = vma_new_array(allocator, char, len + 1);
    -
    18381  if(len > 0)
    -
    18382  {
    -
    18383  memcpy(pChars, sb.GetData(), len);
    -
    18384  }
    -
    18385  pChars[len] = '\0';
    -
    18386  *ppStatsString = pChars;
    -
    18387 }
    -
    18388 
    -
    18389 VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString(
    -
    18390  VmaAllocator allocator,
    -
    18391  char* pStatsString)
    -
    18392 {
    -
    18393  if(pStatsString != VMA_NULL)
    -
    18394  {
    -
    18395  VMA_ASSERT(allocator);
    -
    18396  size_t len = strlen(pStatsString);
    -
    18397  vma_delete_array(allocator, pStatsString, len + 1);
    -
    18398  }
    -
    18399 }
    -
    18400 
    -
    18401 #endif // #if VMA_STATS_STRING_ENABLED
    -
    18402 
    -
    18403 /*
    -
    18404 This function is not protected by any mutex because it just reads immutable data.
    -
    18405 */
    -
    18406 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
    -
    18407  VmaAllocator allocator,
    -
    18408  uint32_t memoryTypeBits,
    -
    18409  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    -
    18410  uint32_t* pMemoryTypeIndex)
    -
    18411 {
    -
    18412  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    -
    18413  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
    -
    18414  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    +
    18356 #if VMA_VULKAN_VERSION >= 1001000
    +
    18357  if((flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0)
    +
    18358  {
    +
    18359  json.WriteString("PROTECTED");
    +
    18360  }
    +
    18361 #endif // #if VMA_VULKAN_VERSION >= 1001000
    +
    18362 #if VK_AMD_device_coherent_memory
    +
    18363  if((flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
    +
    18364  {
    +
    18365  json.WriteString("DEVICE_COHERENT");
    +
    18366  }
    +
    18367  if((flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) != 0)
    +
    18368  {
    +
    18369  json.WriteString("DEVICE_UNCACHED");
    +
    18370  }
    +
    18371 #endif // #if VK_AMD_device_coherent_memory
    +
    18372  json.EndArray();
    +
    18373 
    +
    18374  if(stats.memoryType[typeIndex].blockCount > 0)
    +
    18375  {
    +
    18376  json.WriteString("Stats");
    +
    18377  VmaPrintStatInfo(json, stats.memoryType[typeIndex]);
    +
    18378  }
    +
    18379 
    +
    18380  json.EndObject();
    +
    18381  }
    +
    18382  }
    +
    18383 
    +
    18384  json.EndObject();
    +
    18385  }
    +
    18386  if(detailedMap == VK_TRUE)
    +
    18387  {
    +
    18388  allocator->PrintDetailedMap(json);
    +
    18389  }
    +
    18390 
    +
    18391  json.EndObject();
    +
    18392  }
    +
    18393 
    +
    18394  const size_t len = sb.GetLength();
    +
    18395  char* const pChars = vma_new_array(allocator, char, len + 1);
    +
    18396  if(len > 0)
    +
    18397  {
    +
    18398  memcpy(pChars, sb.GetData(), len);
    +
    18399  }
    +
    18400  pChars[len] = '\0';
    +
    18401  *ppStatsString = pChars;
    +
    18402 }
    +
    18403 
    +
    18404 VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString(
    +
    18405  VmaAllocator allocator,
    +
    18406  char* pStatsString)
    +
    18407 {
    +
    18408  if(pStatsString != VMA_NULL)
    +
    18409  {
    +
    18410  VMA_ASSERT(allocator);
    +
    18411  size_t len = strlen(pStatsString);
    +
    18412  vma_delete_array(allocator, pStatsString, len + 1);
    +
    18413  }
    +
    18414 }
    18415 
    -
    18416  memoryTypeBits &= allocator->GetGlobalMemoryTypeBits();
    +
    18416 #endif // #if VMA_STATS_STRING_ENABLED
    18417 
    -
    18418  if(pAllocationCreateInfo->memoryTypeBits != 0)
    -
    18419  {
    -
    18420  memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits;
    -
    18421  }
    -
    18422 
    -
    18423  uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
    -
    18424  uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
    -
    18425  uint32_t notPreferredFlags = 0;
    -
    18426 
    -
    18427  // Convert usage to requiredFlags and preferredFlags.
    -
    18428  switch(pAllocationCreateInfo->usage)
    -
    18429  {
    -
    18430  case VMA_MEMORY_USAGE_UNKNOWN:
    -
    18431  break;
    -
    18432  case VMA_MEMORY_USAGE_GPU_ONLY:
    -
    18433  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    -
    18434  {
    -
    18435  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    -
    18436  }
    -
    18437  break;
    -
    18438  case VMA_MEMORY_USAGE_CPU_ONLY:
    -
    18439  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    -
    18440  break;
    -
    18441  case VMA_MEMORY_USAGE_CPU_TO_GPU:
    -
    18442  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    -
    18443  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    -
    18444  {
    -
    18445  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    -
    18446  }
    -
    18447  break;
    -
    18448  case VMA_MEMORY_USAGE_GPU_TO_CPU:
    -
    18449  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    -
    18450  preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
    -
    18451  break;
    -
    18452  case VMA_MEMORY_USAGE_CPU_COPY:
    -
    18453  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    -
    18454  break;
    -
    18455  case VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED:
    -
    18456  requiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
    -
    18457  break;
    -
    18458  default:
    -
    18459  VMA_ASSERT(0);
    -
    18460  break;
    -
    18461  }
    -
    18462 
    -
    18463  // Avoid DEVICE_COHERENT unless explicitly requested.
    -
    18464  if(((pAllocationCreateInfo->requiredFlags | pAllocationCreateInfo->preferredFlags) &
    -
    18465  (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0)
    -
    18466  {
    -
    18467  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY;
    -
    18468  }
    -
    18469 
    -
    18470  *pMemoryTypeIndex = UINT32_MAX;
    -
    18471  uint32_t minCost = UINT32_MAX;
    -
    18472  for(uint32_t memTypeIndex = 0, memTypeBit = 1;
    -
    18473  memTypeIndex < allocator->GetMemoryTypeCount();
    -
    18474  ++memTypeIndex, memTypeBit <<= 1)
    -
    18475  {
    -
    18476  // This memory type is acceptable according to memoryTypeBits bitmask.
    -
    18477  if((memTypeBit & memoryTypeBits) != 0)
    -
    18478  {
    -
    18479  const VkMemoryPropertyFlags currFlags =
    -
    18480  allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
    -
    18481  // This memory type contains requiredFlags.
    -
    18482  if((requiredFlags & ~currFlags) == 0)
    -
    18483  {
    -
    18484  // Calculate cost as number of bits from preferredFlags not present in this memory type.
    -
    18485  uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags) +
    -
    18486  VmaCountBitsSet(currFlags & notPreferredFlags);
    -
    18487  // Remember memory type with lowest cost.
    -
    18488  if(currCost < minCost)
    -
    18489  {
    -
    18490  *pMemoryTypeIndex = memTypeIndex;
    -
    18491  if(currCost == 0)
    -
    18492  {
    -
    18493  return VK_SUCCESS;
    -
    18494  }
    -
    18495  minCost = currCost;
    -
    18496  }
    -
    18497  }
    -
    18498  }
    -
    18499  }
    -
    18500  return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
    -
    18501 }
    -
    18502 
    -
    18503 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo(
    -
    18504  VmaAllocator allocator,
    -
    18505  const VkBufferCreateInfo* pBufferCreateInfo,
    -
    18506  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    -
    18507  uint32_t* pMemoryTypeIndex)
    -
    18508 {
    -
    18509  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    -
    18510  VMA_ASSERT(pBufferCreateInfo != VMA_NULL);
    -
    18511  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
    -
    18512  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    -
    18513 
    -
    18514  const VkDevice hDev = allocator->m_hDevice;
    -
    18515  VkBuffer hBuffer = VK_NULL_HANDLE;
    -
    18516  VkResult res = allocator->GetVulkanFunctions().vkCreateBuffer(
    -
    18517  hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer);
    -
    18518  if(res == VK_SUCCESS)
    -
    18519  {
    -
    18520  VkMemoryRequirements memReq = {};
    -
    18521  allocator->GetVulkanFunctions().vkGetBufferMemoryRequirements(
    -
    18522  hDev, hBuffer, &memReq);
    -
    18523 
    -
    18524  res = vmaFindMemoryTypeIndex(
    -
    18525  allocator,
    -
    18526  memReq.memoryTypeBits,
    -
    18527  pAllocationCreateInfo,
    -
    18528  pMemoryTypeIndex);
    -
    18529 
    -
    18530  allocator->GetVulkanFunctions().vkDestroyBuffer(
    -
    18531  hDev, hBuffer, allocator->GetAllocationCallbacks());
    -
    18532  }
    -
    18533  return res;
    -
    18534 }
    -
    18535 
    -
    18536 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo(
    -
    18537  VmaAllocator allocator,
    -
    18538  const VkImageCreateInfo* pImageCreateInfo,
    -
    18539  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    -
    18540  uint32_t* pMemoryTypeIndex)
    -
    18541 {
    -
    18542  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    -
    18543  VMA_ASSERT(pImageCreateInfo != VMA_NULL);
    -
    18544  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
    -
    18545  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    -
    18546 
    -
    18547  const VkDevice hDev = allocator->m_hDevice;
    -
    18548  VkImage hImage = VK_NULL_HANDLE;
    -
    18549  VkResult res = allocator->GetVulkanFunctions().vkCreateImage(
    -
    18550  hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage);
    -
    18551  if(res == VK_SUCCESS)
    -
    18552  {
    -
    18553  VkMemoryRequirements memReq = {};
    -
    18554  allocator->GetVulkanFunctions().vkGetImageMemoryRequirements(
    -
    18555  hDev, hImage, &memReq);
    -
    18556 
    -
    18557  res = vmaFindMemoryTypeIndex(
    -
    18558  allocator,
    -
    18559  memReq.memoryTypeBits,
    -
    18560  pAllocationCreateInfo,
    -
    18561  pMemoryTypeIndex);
    -
    18562 
    -
    18563  allocator->GetVulkanFunctions().vkDestroyImage(
    -
    18564  hDev, hImage, allocator->GetAllocationCallbacks());
    -
    18565  }
    -
    18566  return res;
    -
    18567 }
    -
    18568 
    -
    18569 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool(
    -
    18570  VmaAllocator allocator,
    -
    18571  const VmaPoolCreateInfo* pCreateInfo,
    -
    18572  VmaPool* pPool)
    -
    18573 {
    -
    18574  VMA_ASSERT(allocator && pCreateInfo && pPool);
    -
    18575 
    -
    18576  VMA_DEBUG_LOG("vmaCreatePool");
    +
    18418 /*
    +
    18419 This function is not protected by any mutex because it just reads immutable data.
    +
    18420 */
    +
    18421 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
    +
    18422  VmaAllocator allocator,
    +
    18423  uint32_t memoryTypeBits,
    +
    18424  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    +
    18425  uint32_t* pMemoryTypeIndex)
    +
    18426 {
    +
    18427  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    +
    18428  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
    +
    18429  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    +
    18430 
    +
    18431  memoryTypeBits &= allocator->GetGlobalMemoryTypeBits();
    +
    18432 
    +
    18433  if(pAllocationCreateInfo->memoryTypeBits != 0)
    +
    18434  {
    +
    18435  memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits;
    +
    18436  }
    +
    18437 
    +
    18438  uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
    +
    18439  uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
    +
    18440  uint32_t notPreferredFlags = 0;
    +
    18441 
    +
    18442  // Convert usage to requiredFlags and preferredFlags.
    +
    18443  switch(pAllocationCreateInfo->usage)
    +
    18444  {
    +
    18445  case VMA_MEMORY_USAGE_UNKNOWN:
    +
    18446  break;
    +
    18447  case VMA_MEMORY_USAGE_GPU_ONLY:
    +
    18448  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    +
    18449  {
    +
    18450  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    +
    18451  }
    +
    18452  break;
    +
    18453  case VMA_MEMORY_USAGE_CPU_ONLY:
    +
    18454  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    +
    18455  break;
    +
    18456  case VMA_MEMORY_USAGE_CPU_TO_GPU:
    +
    18457  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    +
    18458  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
    +
    18459  {
    +
    18460  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    +
    18461  }
    +
    18462  break;
    +
    18463  case VMA_MEMORY_USAGE_GPU_TO_CPU:
    +
    18464  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    +
    18465  preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
    +
    18466  break;
    +
    18467  case VMA_MEMORY_USAGE_CPU_COPY:
    +
    18468  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    +
    18469  break;
    +
    18470  case VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED:
    +
    18471  requiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
    +
    18472  break;
    +
    18473  default:
    +
    18474  VMA_ASSERT(0);
    +
    18475  break;
    +
    18476  }
    +
    18477 
    +
    18478  // Avoid DEVICE_COHERENT unless explicitly requested.
    +
    18479  if(((pAllocationCreateInfo->requiredFlags | pAllocationCreateInfo->preferredFlags) &
    +
    18480  (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0)
    +
    18481  {
    +
    18482  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY;
    +
    18483  }
    +
    18484 
    +
    18485  *pMemoryTypeIndex = UINT32_MAX;
    +
    18486  uint32_t minCost = UINT32_MAX;
    +
    18487  for(uint32_t memTypeIndex = 0, memTypeBit = 1;
    +
    18488  memTypeIndex < allocator->GetMemoryTypeCount();
    +
    18489  ++memTypeIndex, memTypeBit <<= 1)
    +
    18490  {
    +
    18491  // This memory type is acceptable according to memoryTypeBits bitmask.
    +
    18492  if((memTypeBit & memoryTypeBits) != 0)
    +
    18493  {
    +
    18494  const VkMemoryPropertyFlags currFlags =
    +
    18495  allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
    +
    18496  // This memory type contains requiredFlags.
    +
    18497  if((requiredFlags & ~currFlags) == 0)
    +
    18498  {
    +
    18499  // Calculate cost as number of bits from preferredFlags not present in this memory type.
    +
    18500  uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags) +
    +
    18501  VmaCountBitsSet(currFlags & notPreferredFlags);
    +
    18502  // Remember memory type with lowest cost.
    +
    18503  if(currCost < minCost)
    +
    18504  {
    +
    18505  *pMemoryTypeIndex = memTypeIndex;
    +
    18506  if(currCost == 0)
    +
    18507  {
    +
    18508  return VK_SUCCESS;
    +
    18509  }
    +
    18510  minCost = currCost;
    +
    18511  }
    +
    18512  }
    +
    18513  }
    +
    18514  }
    +
    18515  return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
    +
    18516 }
    +
    18517 
    +
    18518 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo(
    +
    18519  VmaAllocator allocator,
    +
    18520  const VkBufferCreateInfo* pBufferCreateInfo,
    +
    18521  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    +
    18522  uint32_t* pMemoryTypeIndex)
    +
    18523 {
    +
    18524  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    +
    18525  VMA_ASSERT(pBufferCreateInfo != VMA_NULL);
    +
    18526  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
    +
    18527  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    +
    18528 
    +
    18529  const VkDevice hDev = allocator->m_hDevice;
    +
    18530  VkBuffer hBuffer = VK_NULL_HANDLE;
    +
    18531  VkResult res = allocator->GetVulkanFunctions().vkCreateBuffer(
    +
    18532  hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer);
    +
    18533  if(res == VK_SUCCESS)
    +
    18534  {
    +
    18535  VkMemoryRequirements memReq = {};
    +
    18536  allocator->GetVulkanFunctions().vkGetBufferMemoryRequirements(
    +
    18537  hDev, hBuffer, &memReq);
    +
    18538 
    +
    18539  res = vmaFindMemoryTypeIndex(
    +
    18540  allocator,
    +
    18541  memReq.memoryTypeBits,
    +
    18542  pAllocationCreateInfo,
    +
    18543  pMemoryTypeIndex);
    +
    18544 
    +
    18545  allocator->GetVulkanFunctions().vkDestroyBuffer(
    +
    18546  hDev, hBuffer, allocator->GetAllocationCallbacks());
    +
    18547  }
    +
    18548  return res;
    +
    18549 }
    +
    18550 
    +
    18551 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo(
    +
    18552  VmaAllocator allocator,
    +
    18553  const VkImageCreateInfo* pImageCreateInfo,
    +
    18554  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    +
    18555  uint32_t* pMemoryTypeIndex)
    +
    18556 {
    +
    18557  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    +
    18558  VMA_ASSERT(pImageCreateInfo != VMA_NULL);
    +
    18559  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
    +
    18560  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    +
    18561 
    +
    18562  const VkDevice hDev = allocator->m_hDevice;
    +
    18563  VkImage hImage = VK_NULL_HANDLE;
    +
    18564  VkResult res = allocator->GetVulkanFunctions().vkCreateImage(
    +
    18565  hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage);
    +
    18566  if(res == VK_SUCCESS)
    +
    18567  {
    +
    18568  VkMemoryRequirements memReq = {};
    +
    18569  allocator->GetVulkanFunctions().vkGetImageMemoryRequirements(
    +
    18570  hDev, hImage, &memReq);
    +
    18571 
    +
    18572  res = vmaFindMemoryTypeIndex(
    +
    18573  allocator,
    +
    18574  memReq.memoryTypeBits,
    +
    18575  pAllocationCreateInfo,
    +
    18576  pMemoryTypeIndex);
    18577 
    -
    18578  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18579 
    -
    18580  VkResult res = allocator->CreatePool(pCreateInfo, pPool);
    -
    18581 
    -
    18582 #if VMA_RECORDING_ENABLED
    -
    18583  if(allocator->GetRecorder() != VMA_NULL)
    -
    18584  {
    -
    18585  allocator->GetRecorder()->RecordCreatePool(allocator->GetCurrentFrameIndex(), *pCreateInfo, *pPool);
    -
    18586  }
    -
    18587 #endif
    -
    18588 
    -
    18589  return res;
    -
    18590 }
    -
    18591 
    -
    18592 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool(
    -
    18593  VmaAllocator allocator,
    -
    18594  VmaPool pool)
    -
    18595 {
    -
    18596  VMA_ASSERT(allocator);
    -
    18597 
    -
    18598  if(pool == VK_NULL_HANDLE)
    +
    18578  allocator->GetVulkanFunctions().vkDestroyImage(
    +
    18579  hDev, hImage, allocator->GetAllocationCallbacks());
    +
    18580  }
    +
    18581  return res;
    +
    18582 }
    +
    18583 
    +
    18584 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool(
    +
    18585  VmaAllocator allocator,
    +
    18586  const VmaPoolCreateInfo* pCreateInfo,
    +
    18587  VmaPool* pPool)
    +
    18588 {
    +
    18589  VMA_ASSERT(allocator && pCreateInfo && pPool);
    +
    18590 
    +
    18591  VMA_DEBUG_LOG("vmaCreatePool");
    +
    18592 
    +
    18593  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18594 
    +
    18595  VkResult res = allocator->CreatePool(pCreateInfo, pPool);
    +
    18596 
    +
    18597 #if VMA_RECORDING_ENABLED
    +
    18598  if(allocator->GetRecorder() != VMA_NULL)
    18599  {
    -
    18600  return;
    +
    18600  allocator->GetRecorder()->RecordCreatePool(allocator->GetCurrentFrameIndex(), *pCreateInfo, *pPool);
    18601  }
    -
    18602 
    -
    18603  VMA_DEBUG_LOG("vmaDestroyPool");
    -
    18604 
    -
    18605  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18602 #endif
    +
    18603 
    +
    18604  return res;
    +
    18605 }
    18606 
    -
    18607 #if VMA_RECORDING_ENABLED
    -
    18608  if(allocator->GetRecorder() != VMA_NULL)
    -
    18609  {
    -
    18610  allocator->GetRecorder()->RecordDestroyPool(allocator->GetCurrentFrameIndex(), pool);
    -
    18611  }
    -
    18612 #endif
    -
    18613 
    -
    18614  allocator->DestroyPool(pool);
    -
    18615 }
    -
    18616 
    -
    18617 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats(
    -
    18618  VmaAllocator allocator,
    -
    18619  VmaPool pool,
    -
    18620  VmaPoolStats* pPoolStats)
    -
    18621 {
    -
    18622  VMA_ASSERT(allocator && pool && pPoolStats);
    -
    18623 
    -
    18624  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18625 
    -
    18626  allocator->GetPoolStats(pool, pPoolStats);
    -
    18627 }
    +
    18607 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool(
    +
    18608  VmaAllocator allocator,
    +
    18609  VmaPool pool)
    +
    18610 {
    +
    18611  VMA_ASSERT(allocator);
    +
    18612 
    +
    18613  if(pool == VK_NULL_HANDLE)
    +
    18614  {
    +
    18615  return;
    +
    18616  }
    +
    18617 
    +
    18618  VMA_DEBUG_LOG("vmaDestroyPool");
    +
    18619 
    +
    18620  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18621 
    +
    18622 #if VMA_RECORDING_ENABLED
    +
    18623  if(allocator->GetRecorder() != VMA_NULL)
    +
    18624  {
    +
    18625  allocator->GetRecorder()->RecordDestroyPool(allocator->GetCurrentFrameIndex(), pool);
    +
    18626  }
    +
    18627 #endif
    18628 
    -
    18629 VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost(
    -
    18630  VmaAllocator allocator,
    -
    18631  VmaPool pool,
    -
    18632  size_t* pLostAllocationCount)
    -
    18633 {
    -
    18634  VMA_ASSERT(allocator && pool);
    -
    18635 
    -
    18636  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18637 
    -
    18638 #if VMA_RECORDING_ENABLED
    -
    18639  if(allocator->GetRecorder() != VMA_NULL)
    -
    18640  {
    -
    18641  allocator->GetRecorder()->RecordMakePoolAllocationsLost(allocator->GetCurrentFrameIndex(), pool);
    -
    18642  }
    -
    18643 #endif
    -
    18644 
    -
    18645  allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
    -
    18646 }
    -
    18647 
    -
    18648 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool)
    -
    18649 {
    -
    18650  VMA_ASSERT(allocator && pool);
    -
    18651 
    -
    18652  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18653 
    -
    18654  VMA_DEBUG_LOG("vmaCheckPoolCorruption");
    -
    18655 
    -
    18656  return allocator->CheckPoolCorruption(pool);
    -
    18657 }
    -
    18658 
    -
    18659 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName(
    -
    18660  VmaAllocator allocator,
    -
    18661  VmaPool pool,
    -
    18662  const char** ppName)
    -
    18663 {
    -
    18664  VMA_ASSERT(allocator && pool && ppName);
    -
    18665 
    -
    18666  VMA_DEBUG_LOG("vmaGetPoolName");
    -
    18667 
    -
    18668  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18669 
    -
    18670  *ppName = pool->GetName();
    -
    18671 }
    -
    18672 
    -
    18673 VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName(
    -
    18674  VmaAllocator allocator,
    -
    18675  VmaPool pool,
    -
    18676  const char* pName)
    -
    18677 {
    -
    18678  VMA_ASSERT(allocator && pool);
    -
    18679 
    -
    18680  VMA_DEBUG_LOG("vmaSetPoolName");
    -
    18681 
    -
    18682  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18683 
    -
    18684  pool->SetName(pName);
    -
    18685 
    -
    18686 #if VMA_RECORDING_ENABLED
    -
    18687  if(allocator->GetRecorder() != VMA_NULL)
    -
    18688  {
    -
    18689  allocator->GetRecorder()->RecordSetPoolName(allocator->GetCurrentFrameIndex(), pool, pName);
    -
    18690  }
    -
    18691 #endif
    -
    18692 }
    -
    18693 
    -
    18694 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory(
    -
    18695  VmaAllocator allocator,
    -
    18696  const VkMemoryRequirements* pVkMemoryRequirements,
    -
    18697  const VmaAllocationCreateInfo* pCreateInfo,
    -
    18698  VmaAllocation* pAllocation,
    -
    18699  VmaAllocationInfo* pAllocationInfo)
    -
    18700 {
    -
    18701  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation);
    -
    18702 
    -
    18703  VMA_DEBUG_LOG("vmaAllocateMemory");
    -
    18704 
    -
    18705  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18706 
    -
    18707  VkResult result = allocator->AllocateMemory(
    -
    18708  *pVkMemoryRequirements,
    -
    18709  false, // requiresDedicatedAllocation
    -
    18710  false, // prefersDedicatedAllocation
    -
    18711  VK_NULL_HANDLE, // dedicatedBuffer
    -
    18712  UINT32_MAX, // dedicatedBufferUsage
    -
    18713  VK_NULL_HANDLE, // dedicatedImage
    -
    18714  *pCreateInfo,
    -
    18715  VMA_SUBALLOCATION_TYPE_UNKNOWN,
    -
    18716  1, // allocationCount
    -
    18717  pAllocation);
    -
    18718 
    -
    18719 #if VMA_RECORDING_ENABLED
    -
    18720  if(allocator->GetRecorder() != VMA_NULL)
    -
    18721  {
    -
    18722  allocator->GetRecorder()->RecordAllocateMemory(
    -
    18723  allocator->GetCurrentFrameIndex(),
    -
    18724  *pVkMemoryRequirements,
    -
    18725  *pCreateInfo,
    -
    18726  *pAllocation);
    -
    18727  }
    -
    18728 #endif
    -
    18729 
    -
    18730  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
    -
    18731  {
    -
    18732  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    -
    18733  }
    -
    18734 
    -
    18735  return result;
    -
    18736 }
    -
    18737 
    -
    18738 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages(
    -
    18739  VmaAllocator allocator,
    -
    18740  const VkMemoryRequirements* pVkMemoryRequirements,
    -
    18741  const VmaAllocationCreateInfo* pCreateInfo,
    -
    18742  size_t allocationCount,
    -
    18743  VmaAllocation* pAllocations,
    -
    18744  VmaAllocationInfo* pAllocationInfo)
    -
    18745 {
    -
    18746  if(allocationCount == 0)
    -
    18747  {
    -
    18748  return VK_SUCCESS;
    -
    18749  }
    -
    18750 
    -
    18751  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations);
    +
    18629  allocator->DestroyPool(pool);
    +
    18630 }
    +
    18631 
    +
    18632 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats(
    +
    18633  VmaAllocator allocator,
    +
    18634  VmaPool pool,
    +
    18635  VmaPoolStats* pPoolStats)
    +
    18636 {
    +
    18637  VMA_ASSERT(allocator && pool && pPoolStats);
    +
    18638 
    +
    18639  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18640 
    +
    18641  allocator->GetPoolStats(pool, pPoolStats);
    +
    18642 }
    +
    18643 
    +
    18644 VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost(
    +
    18645  VmaAllocator allocator,
    +
    18646  VmaPool pool,
    +
    18647  size_t* pLostAllocationCount)
    +
    18648 {
    +
    18649  VMA_ASSERT(allocator && pool);
    +
    18650 
    +
    18651  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18652 
    +
    18653 #if VMA_RECORDING_ENABLED
    +
    18654  if(allocator->GetRecorder() != VMA_NULL)
    +
    18655  {
    +
    18656  allocator->GetRecorder()->RecordMakePoolAllocationsLost(allocator->GetCurrentFrameIndex(), pool);
    +
    18657  }
    +
    18658 #endif
    +
    18659 
    +
    18660  allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
    +
    18661 }
    +
    18662 
    +
    18663 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool)
    +
    18664 {
    +
    18665  VMA_ASSERT(allocator && pool);
    +
    18666 
    +
    18667  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18668 
    +
    18669  VMA_DEBUG_LOG("vmaCheckPoolCorruption");
    +
    18670 
    +
    18671  return allocator->CheckPoolCorruption(pool);
    +
    18672 }
    +
    18673 
    +
    18674 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName(
    +
    18675  VmaAllocator allocator,
    +
    18676  VmaPool pool,
    +
    18677  const char** ppName)
    +
    18678 {
    +
    18679  VMA_ASSERT(allocator && pool && ppName);
    +
    18680 
    +
    18681  VMA_DEBUG_LOG("vmaGetPoolName");
    +
    18682 
    +
    18683  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18684 
    +
    18685  *ppName = pool->GetName();
    +
    18686 }
    +
    18687 
    +
    18688 VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName(
    +
    18689  VmaAllocator allocator,
    +
    18690  VmaPool pool,
    +
    18691  const char* pName)
    +
    18692 {
    +
    18693  VMA_ASSERT(allocator && pool);
    +
    18694 
    +
    18695  VMA_DEBUG_LOG("vmaSetPoolName");
    +
    18696 
    +
    18697  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18698 
    +
    18699  pool->SetName(pName);
    +
    18700 
    +
    18701 #if VMA_RECORDING_ENABLED
    +
    18702  if(allocator->GetRecorder() != VMA_NULL)
    +
    18703  {
    +
    18704  allocator->GetRecorder()->RecordSetPoolName(allocator->GetCurrentFrameIndex(), pool, pName);
    +
    18705  }
    +
    18706 #endif
    +
    18707 }
    +
    18708 
    +
    18709 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory(
    +
    18710  VmaAllocator allocator,
    +
    18711  const VkMemoryRequirements* pVkMemoryRequirements,
    +
    18712  const VmaAllocationCreateInfo* pCreateInfo,
    +
    18713  VmaAllocation* pAllocation,
    +
    18714  VmaAllocationInfo* pAllocationInfo)
    +
    18715 {
    +
    18716  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation);
    +
    18717 
    +
    18718  VMA_DEBUG_LOG("vmaAllocateMemory");
    +
    18719 
    +
    18720  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18721 
    +
    18722  VkResult result = allocator->AllocateMemory(
    +
    18723  *pVkMemoryRequirements,
    +
    18724  false, // requiresDedicatedAllocation
    +
    18725  false, // prefersDedicatedAllocation
    +
    18726  VK_NULL_HANDLE, // dedicatedBuffer
    +
    18727  UINT32_MAX, // dedicatedBufferUsage
    +
    18728  VK_NULL_HANDLE, // dedicatedImage
    +
    18729  *pCreateInfo,
    +
    18730  VMA_SUBALLOCATION_TYPE_UNKNOWN,
    +
    18731  1, // allocationCount
    +
    18732  pAllocation);
    +
    18733 
    +
    18734 #if VMA_RECORDING_ENABLED
    +
    18735  if(allocator->GetRecorder() != VMA_NULL)
    +
    18736  {
    +
    18737  allocator->GetRecorder()->RecordAllocateMemory(
    +
    18738  allocator->GetCurrentFrameIndex(),
    +
    18739  *pVkMemoryRequirements,
    +
    18740  *pCreateInfo,
    +
    18741  *pAllocation);
    +
    18742  }
    +
    18743 #endif
    +
    18744 
    +
    18745  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
    +
    18746  {
    +
    18747  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    +
    18748  }
    +
    18749 
    +
    18750  return result;
    +
    18751 }
    18752 
    -
    18753  VMA_DEBUG_LOG("vmaAllocateMemoryPages");
    -
    18754 
    -
    18755  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18756 
    -
    18757  VkResult result = allocator->AllocateMemory(
    -
    18758  *pVkMemoryRequirements,
    -
    18759  false, // requiresDedicatedAllocation
    -
    18760  false, // prefersDedicatedAllocation
    -
    18761  VK_NULL_HANDLE, // dedicatedBuffer
    -
    18762  UINT32_MAX, // dedicatedBufferUsage
    -
    18763  VK_NULL_HANDLE, // dedicatedImage
    -
    18764  *pCreateInfo,
    -
    18765  VMA_SUBALLOCATION_TYPE_UNKNOWN,
    -
    18766  allocationCount,
    -
    18767  pAllocations);
    -
    18768 
    -
    18769 #if VMA_RECORDING_ENABLED
    -
    18770  if(allocator->GetRecorder() != VMA_NULL)
    -
    18771  {
    -
    18772  allocator->GetRecorder()->RecordAllocateMemoryPages(
    -
    18773  allocator->GetCurrentFrameIndex(),
    -
    18774  *pVkMemoryRequirements,
    -
    18775  *pCreateInfo,
    -
    18776  (uint64_t)allocationCount,
    -
    18777  pAllocations);
    -
    18778  }
    -
    18779 #endif
    -
    18780 
    -
    18781  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
    -
    18782  {
    -
    18783  for(size_t i = 0; i < allocationCount; ++i)
    -
    18784  {
    -
    18785  allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i);
    -
    18786  }
    -
    18787  }
    -
    18788 
    -
    18789  return result;
    -
    18790 }
    -
    18791 
    -
    18792 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer(
    -
    18793  VmaAllocator allocator,
    -
    18794  VkBuffer buffer,
    -
    18795  const VmaAllocationCreateInfo* pCreateInfo,
    -
    18796  VmaAllocation* pAllocation,
    -
    18797  VmaAllocationInfo* pAllocationInfo)
    -
    18798 {
    -
    18799  VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation);
    -
    18800 
    -
    18801  VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
    -
    18802 
    -
    18803  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18804 
    -
    18805  VkMemoryRequirements vkMemReq = {};
    -
    18806  bool requiresDedicatedAllocation = false;
    -
    18807  bool prefersDedicatedAllocation = false;
    -
    18808  allocator->GetBufferMemoryRequirements(buffer, vkMemReq,
    -
    18809  requiresDedicatedAllocation,
    -
    18810  prefersDedicatedAllocation);
    -
    18811 
    -
    18812  VkResult result = allocator->AllocateMemory(
    -
    18813  vkMemReq,
    -
    18814  requiresDedicatedAllocation,
    -
    18815  prefersDedicatedAllocation,
    -
    18816  buffer, // dedicatedBuffer
    -
    18817  UINT32_MAX, // dedicatedBufferUsage
    -
    18818  VK_NULL_HANDLE, // dedicatedImage
    -
    18819  *pCreateInfo,
    -
    18820  VMA_SUBALLOCATION_TYPE_BUFFER,
    -
    18821  1, // allocationCount
    -
    18822  pAllocation);
    -
    18823 
    -
    18824 #if VMA_RECORDING_ENABLED
    -
    18825  if(allocator->GetRecorder() != VMA_NULL)
    -
    18826  {
    -
    18827  allocator->GetRecorder()->RecordAllocateMemoryForBuffer(
    -
    18828  allocator->GetCurrentFrameIndex(),
    -
    18829  vkMemReq,
    -
    18830  requiresDedicatedAllocation,
    -
    18831  prefersDedicatedAllocation,
    -
    18832  *pCreateInfo,
    -
    18833  *pAllocation);
    -
    18834  }
    -
    18835 #endif
    -
    18836 
    -
    18837  if(pAllocationInfo && result == VK_SUCCESS)
    -
    18838  {
    -
    18839  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    -
    18840  }
    -
    18841 
    -
    18842  return result;
    -
    18843 }
    -
    18844 
    -
    18845 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage(
    -
    18846  VmaAllocator allocator,
    -
    18847  VkImage image,
    -
    18848  const VmaAllocationCreateInfo* pCreateInfo,
    -
    18849  VmaAllocation* pAllocation,
    -
    18850  VmaAllocationInfo* pAllocationInfo)
    -
    18851 {
    -
    18852  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation);
    -
    18853 
    -
    18854  VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
    -
    18855 
    -
    18856  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18857 
    -
    18858  VkMemoryRequirements vkMemReq = {};
    -
    18859  bool requiresDedicatedAllocation = false;
    -
    18860  bool prefersDedicatedAllocation = false;
    -
    18861  allocator->GetImageMemoryRequirements(image, vkMemReq,
    -
    18862  requiresDedicatedAllocation, prefersDedicatedAllocation);
    -
    18863 
    -
    18864  VkResult result = allocator->AllocateMemory(
    -
    18865  vkMemReq,
    -
    18866  requiresDedicatedAllocation,
    -
    18867  prefersDedicatedAllocation,
    -
    18868  VK_NULL_HANDLE, // dedicatedBuffer
    -
    18869  UINT32_MAX, // dedicatedBufferUsage
    -
    18870  image, // dedicatedImage
    -
    18871  *pCreateInfo,
    -
    18872  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
    -
    18873  1, // allocationCount
    -
    18874  pAllocation);
    -
    18875 
    -
    18876 #if VMA_RECORDING_ENABLED
    -
    18877  if(allocator->GetRecorder() != VMA_NULL)
    -
    18878  {
    -
    18879  allocator->GetRecorder()->RecordAllocateMemoryForImage(
    -
    18880  allocator->GetCurrentFrameIndex(),
    -
    18881  vkMemReq,
    -
    18882  requiresDedicatedAllocation,
    -
    18883  prefersDedicatedAllocation,
    -
    18884  *pCreateInfo,
    -
    18885  *pAllocation);
    -
    18886  }
    -
    18887 #endif
    -
    18888 
    -
    18889  if(pAllocationInfo && result == VK_SUCCESS)
    -
    18890  {
    -
    18891  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    -
    18892  }
    -
    18893 
    -
    18894  return result;
    -
    18895 }
    -
    18896 
    -
    18897 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory(
    -
    18898  VmaAllocator allocator,
    -
    18899  VmaAllocation allocation)
    -
    18900 {
    -
    18901  VMA_ASSERT(allocator);
    -
    18902 
    -
    18903  if(allocation == VK_NULL_HANDLE)
    -
    18904  {
    -
    18905  return;
    -
    18906  }
    -
    18907 
    -
    18908  VMA_DEBUG_LOG("vmaFreeMemory");
    -
    18909 
    -
    18910  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18753 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages(
    +
    18754  VmaAllocator allocator,
    +
    18755  const VkMemoryRequirements* pVkMemoryRequirements,
    +
    18756  const VmaAllocationCreateInfo* pCreateInfo,
    +
    18757  size_t allocationCount,
    +
    18758  VmaAllocation* pAllocations,
    +
    18759  VmaAllocationInfo* pAllocationInfo)
    +
    18760 {
    +
    18761  if(allocationCount == 0)
    +
    18762  {
    +
    18763  return VK_SUCCESS;
    +
    18764  }
    +
    18765 
    +
    18766  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations);
    +
    18767 
    +
    18768  VMA_DEBUG_LOG("vmaAllocateMemoryPages");
    +
    18769 
    +
    18770  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18771 
    +
    18772  VkResult result = allocator->AllocateMemory(
    +
    18773  *pVkMemoryRequirements,
    +
    18774  false, // requiresDedicatedAllocation
    +
    18775  false, // prefersDedicatedAllocation
    +
    18776  VK_NULL_HANDLE, // dedicatedBuffer
    +
    18777  UINT32_MAX, // dedicatedBufferUsage
    +
    18778  VK_NULL_HANDLE, // dedicatedImage
    +
    18779  *pCreateInfo,
    +
    18780  VMA_SUBALLOCATION_TYPE_UNKNOWN,
    +
    18781  allocationCount,
    +
    18782  pAllocations);
    +
    18783 
    +
    18784 #if VMA_RECORDING_ENABLED
    +
    18785  if(allocator->GetRecorder() != VMA_NULL)
    +
    18786  {
    +
    18787  allocator->GetRecorder()->RecordAllocateMemoryPages(
    +
    18788  allocator->GetCurrentFrameIndex(),
    +
    18789  *pVkMemoryRequirements,
    +
    18790  *pCreateInfo,
    +
    18791  (uint64_t)allocationCount,
    +
    18792  pAllocations);
    +
    18793  }
    +
    18794 #endif
    +
    18795 
    +
    18796  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
    +
    18797  {
    +
    18798  for(size_t i = 0; i < allocationCount; ++i)
    +
    18799  {
    +
    18800  allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i);
    +
    18801  }
    +
    18802  }
    +
    18803 
    +
    18804  return result;
    +
    18805 }
    +
    18806 
    +
    18807 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer(
    +
    18808  VmaAllocator allocator,
    +
    18809  VkBuffer buffer,
    +
    18810  const VmaAllocationCreateInfo* pCreateInfo,
    +
    18811  VmaAllocation* pAllocation,
    +
    18812  VmaAllocationInfo* pAllocationInfo)
    +
    18813 {
    +
    18814  VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation);
    +
    18815 
    +
    18816  VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
    +
    18817 
    +
    18818  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18819 
    +
    18820  VkMemoryRequirements vkMemReq = {};
    +
    18821  bool requiresDedicatedAllocation = false;
    +
    18822  bool prefersDedicatedAllocation = false;
    +
    18823  allocator->GetBufferMemoryRequirements(buffer, vkMemReq,
    +
    18824  requiresDedicatedAllocation,
    +
    18825  prefersDedicatedAllocation);
    +
    18826 
    +
    18827  VkResult result = allocator->AllocateMemory(
    +
    18828  vkMemReq,
    +
    18829  requiresDedicatedAllocation,
    +
    18830  prefersDedicatedAllocation,
    +
    18831  buffer, // dedicatedBuffer
    +
    18832  UINT32_MAX, // dedicatedBufferUsage
    +
    18833  VK_NULL_HANDLE, // dedicatedImage
    +
    18834  *pCreateInfo,
    +
    18835  VMA_SUBALLOCATION_TYPE_BUFFER,
    +
    18836  1, // allocationCount
    +
    18837  pAllocation);
    +
    18838 
    +
    18839 #if VMA_RECORDING_ENABLED
    +
    18840  if(allocator->GetRecorder() != VMA_NULL)
    +
    18841  {
    +
    18842  allocator->GetRecorder()->RecordAllocateMemoryForBuffer(
    +
    18843  allocator->GetCurrentFrameIndex(),
    +
    18844  vkMemReq,
    +
    18845  requiresDedicatedAllocation,
    +
    18846  prefersDedicatedAllocation,
    +
    18847  *pCreateInfo,
    +
    18848  *pAllocation);
    +
    18849  }
    +
    18850 #endif
    +
    18851 
    +
    18852  if(pAllocationInfo && result == VK_SUCCESS)
    +
    18853  {
    +
    18854  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    +
    18855  }
    +
    18856 
    +
    18857  return result;
    +
    18858 }
    +
    18859 
    +
    18860 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage(
    +
    18861  VmaAllocator allocator,
    +
    18862  VkImage image,
    +
    18863  const VmaAllocationCreateInfo* pCreateInfo,
    +
    18864  VmaAllocation* pAllocation,
    +
    18865  VmaAllocationInfo* pAllocationInfo)
    +
    18866 {
    +
    18867  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation);
    +
    18868 
    +
    18869  VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
    +
    18870 
    +
    18871  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18872 
    +
    18873  VkMemoryRequirements vkMemReq = {};
    +
    18874  bool requiresDedicatedAllocation = false;
    +
    18875  bool prefersDedicatedAllocation = false;
    +
    18876  allocator->GetImageMemoryRequirements(image, vkMemReq,
    +
    18877  requiresDedicatedAllocation, prefersDedicatedAllocation);
    +
    18878 
    +
    18879  VkResult result = allocator->AllocateMemory(
    +
    18880  vkMemReq,
    +
    18881  requiresDedicatedAllocation,
    +
    18882  prefersDedicatedAllocation,
    +
    18883  VK_NULL_HANDLE, // dedicatedBuffer
    +
    18884  UINT32_MAX, // dedicatedBufferUsage
    +
    18885  image, // dedicatedImage
    +
    18886  *pCreateInfo,
    +
    18887  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
    +
    18888  1, // allocationCount
    +
    18889  pAllocation);
    +
    18890 
    +
    18891 #if VMA_RECORDING_ENABLED
    +
    18892  if(allocator->GetRecorder() != VMA_NULL)
    +
    18893  {
    +
    18894  allocator->GetRecorder()->RecordAllocateMemoryForImage(
    +
    18895  allocator->GetCurrentFrameIndex(),
    +
    18896  vkMemReq,
    +
    18897  requiresDedicatedAllocation,
    +
    18898  prefersDedicatedAllocation,
    +
    18899  *pCreateInfo,
    +
    18900  *pAllocation);
    +
    18901  }
    +
    18902 #endif
    +
    18903 
    +
    18904  if(pAllocationInfo && result == VK_SUCCESS)
    +
    18905  {
    +
    18906  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    +
    18907  }
    +
    18908 
    +
    18909  return result;
    +
    18910 }
    18911 
    -
    18912 #if VMA_RECORDING_ENABLED
    -
    18913  if(allocator->GetRecorder() != VMA_NULL)
    -
    18914  {
    -
    18915  allocator->GetRecorder()->RecordFreeMemory(
    -
    18916  allocator->GetCurrentFrameIndex(),
    -
    18917  allocation);
    -
    18918  }
    -
    18919 #endif
    -
    18920 
    -
    18921  allocator->FreeMemory(
    -
    18922  1, // allocationCount
    -
    18923  &allocation);
    -
    18924 }
    -
    18925 
    -
    18926 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages(
    -
    18927  VmaAllocator allocator,
    -
    18928  size_t allocationCount,
    -
    18929  const VmaAllocation* pAllocations)
    -
    18930 {
    -
    18931  if(allocationCount == 0)
    -
    18932  {
    -
    18933  return;
    -
    18934  }
    +
    18912 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory(
    +
    18913  VmaAllocator allocator,
    +
    18914  VmaAllocation allocation)
    +
    18915 {
    +
    18916  VMA_ASSERT(allocator);
    +
    18917 
    +
    18918  if(allocation == VK_NULL_HANDLE)
    +
    18919  {
    +
    18920  return;
    +
    18921  }
    +
    18922 
    +
    18923  VMA_DEBUG_LOG("vmaFreeMemory");
    +
    18924 
    +
    18925  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18926 
    +
    18927 #if VMA_RECORDING_ENABLED
    +
    18928  if(allocator->GetRecorder() != VMA_NULL)
    +
    18929  {
    +
    18930  allocator->GetRecorder()->RecordFreeMemory(
    +
    18931  allocator->GetCurrentFrameIndex(),
    +
    18932  allocation);
    +
    18933  }
    +
    18934 #endif
    18935 
    -
    18936  VMA_ASSERT(allocator);
    -
    18937 
    -
    18938  VMA_DEBUG_LOG("vmaFreeMemoryPages");
    -
    18939 
    -
    18940  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18941 
    -
    18942 #if VMA_RECORDING_ENABLED
    -
    18943  if(allocator->GetRecorder() != VMA_NULL)
    -
    18944  {
    -
    18945  allocator->GetRecorder()->RecordFreeMemoryPages(
    -
    18946  allocator->GetCurrentFrameIndex(),
    -
    18947  (uint64_t)allocationCount,
    -
    18948  pAllocations);
    +
    18936  allocator->FreeMemory(
    +
    18937  1, // allocationCount
    +
    18938  &allocation);
    +
    18939 }
    +
    18940 
    +
    18941 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages(
    +
    18942  VmaAllocator allocator,
    +
    18943  size_t allocationCount,
    +
    18944  const VmaAllocation* pAllocations)
    +
    18945 {
    +
    18946  if(allocationCount == 0)
    +
    18947  {
    +
    18948  return;
    18949  }
    -
    18950 #endif
    -
    18951 
    -
    18952  allocator->FreeMemory(allocationCount, pAllocations);
    -
    18953 }
    +
    18950 
    +
    18951  VMA_ASSERT(allocator);
    +
    18952 
    +
    18953  VMA_DEBUG_LOG("vmaFreeMemoryPages");
    18954 
    -
    18955 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo(
    -
    18956  VmaAllocator allocator,
    -
    18957  VmaAllocation allocation,
    -
    18958  VmaAllocationInfo* pAllocationInfo)
    -
    18959 {
    -
    18960  VMA_ASSERT(allocator && allocation && pAllocationInfo);
    -
    18961 
    -
    18962  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18963 
    -
    18964 #if VMA_RECORDING_ENABLED
    -
    18965  if(allocator->GetRecorder() != VMA_NULL)
    -
    18966  {
    -
    18967  allocator->GetRecorder()->RecordGetAllocationInfo(
    -
    18968  allocator->GetCurrentFrameIndex(),
    -
    18969  allocation);
    -
    18970  }
    -
    18971 #endif
    -
    18972 
    -
    18973  allocator->GetAllocationInfo(allocation, pAllocationInfo);
    -
    18974 }
    -
    18975 
    -
    18976 VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation(
    -
    18977  VmaAllocator allocator,
    -
    18978  VmaAllocation allocation)
    -
    18979 {
    -
    18980  VMA_ASSERT(allocator && allocation);
    -
    18981 
    -
    18982  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    18983 
    -
    18984 #if VMA_RECORDING_ENABLED
    -
    18985  if(allocator->GetRecorder() != VMA_NULL)
    -
    18986  {
    -
    18987  allocator->GetRecorder()->RecordTouchAllocation(
    -
    18988  allocator->GetCurrentFrameIndex(),
    -
    18989  allocation);
    -
    18990  }
    -
    18991 #endif
    -
    18992 
    -
    18993  return allocator->TouchAllocation(allocation);
    -
    18994 }
    -
    18995 
    -
    18996 VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData(
    -
    18997  VmaAllocator allocator,
    -
    18998  VmaAllocation allocation,
    -
    18999  void* pUserData)
    -
    19000 {
    -
    19001  VMA_ASSERT(allocator && allocation);
    -
    19002 
    -
    19003  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19004 
    -
    19005  allocation->SetUserData(allocator, pUserData);
    -
    19006 
    -
    19007 #if VMA_RECORDING_ENABLED
    -
    19008  if(allocator->GetRecorder() != VMA_NULL)
    -
    19009  {
    -
    19010  allocator->GetRecorder()->RecordSetAllocationUserData(
    -
    19011  allocator->GetCurrentFrameIndex(),
    -
    19012  allocation,
    -
    19013  pUserData);
    -
    19014  }
    -
    19015 #endif
    -
    19016 }
    +
    18955  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18956 
    +
    18957 #if VMA_RECORDING_ENABLED
    +
    18958  if(allocator->GetRecorder() != VMA_NULL)
    +
    18959  {
    +
    18960  allocator->GetRecorder()->RecordFreeMemoryPages(
    +
    18961  allocator->GetCurrentFrameIndex(),
    +
    18962  (uint64_t)allocationCount,
    +
    18963  pAllocations);
    +
    18964  }
    +
    18965 #endif
    +
    18966 
    +
    18967  allocator->FreeMemory(allocationCount, pAllocations);
    +
    18968 }
    +
    18969 
    +
    18970 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo(
    +
    18971  VmaAllocator allocator,
    +
    18972  VmaAllocation allocation,
    +
    18973  VmaAllocationInfo* pAllocationInfo)
    +
    18974 {
    +
    18975  VMA_ASSERT(allocator && allocation && pAllocationInfo);
    +
    18976 
    +
    18977  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18978 
    +
    18979 #if VMA_RECORDING_ENABLED
    +
    18980  if(allocator->GetRecorder() != VMA_NULL)
    +
    18981  {
    +
    18982  allocator->GetRecorder()->RecordGetAllocationInfo(
    +
    18983  allocator->GetCurrentFrameIndex(),
    +
    18984  allocation);
    +
    18985  }
    +
    18986 #endif
    +
    18987 
    +
    18988  allocator->GetAllocationInfo(allocation, pAllocationInfo);
    +
    18989 }
    +
    18990 
    +
    18991 VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation(
    +
    18992  VmaAllocator allocator,
    +
    18993  VmaAllocation allocation)
    +
    18994 {
    +
    18995  VMA_ASSERT(allocator && allocation);
    +
    18996 
    +
    18997  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    18998 
    +
    18999 #if VMA_RECORDING_ENABLED
    +
    19000  if(allocator->GetRecorder() != VMA_NULL)
    +
    19001  {
    +
    19002  allocator->GetRecorder()->RecordTouchAllocation(
    +
    19003  allocator->GetCurrentFrameIndex(),
    +
    19004  allocation);
    +
    19005  }
    +
    19006 #endif
    +
    19007 
    +
    19008  return allocator->TouchAllocation(allocation);
    +
    19009 }
    +
    19010 
    +
    19011 VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData(
    +
    19012  VmaAllocator allocator,
    +
    19013  VmaAllocation allocation,
    +
    19014  void* pUserData)
    +
    19015 {
    +
    19016  VMA_ASSERT(allocator && allocation);
    19017 
    -
    19018 VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation(
    -
    19019  VmaAllocator allocator,
    -
    19020  VmaAllocation* pAllocation)
    -
    19021 {
    -
    19022  VMA_ASSERT(allocator && pAllocation);
    -
    19023 
    -
    19024  VMA_DEBUG_GLOBAL_MUTEX_LOCK;
    -
    19025 
    -
    19026  allocator->CreateLostAllocation(pAllocation);
    -
    19027 
    -
    19028 #if VMA_RECORDING_ENABLED
    -
    19029  if(allocator->GetRecorder() != VMA_NULL)
    -
    19030  {
    -
    19031  allocator->GetRecorder()->RecordCreateLostAllocation(
    -
    19032  allocator->GetCurrentFrameIndex(),
    -
    19033  *pAllocation);
    -
    19034  }
    -
    19035 #endif
    -
    19036 }
    -
    19037 
    -
    19038 VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory(
    -
    19039  VmaAllocator allocator,
    -
    19040  VmaAllocation allocation,
    -
    19041  void** ppData)
    -
    19042 {
    -
    19043  VMA_ASSERT(allocator && allocation && ppData);
    -
    19044 
    -
    19045  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19046 
    -
    19047  VkResult res = allocator->Map(allocation, ppData);
    -
    19048 
    -
    19049 #if VMA_RECORDING_ENABLED
    -
    19050  if(allocator->GetRecorder() != VMA_NULL)
    -
    19051  {
    -
    19052  allocator->GetRecorder()->RecordMapMemory(
    -
    19053  allocator->GetCurrentFrameIndex(),
    -
    19054  allocation);
    -
    19055  }
    -
    19056 #endif
    -
    19057 
    -
    19058  return res;
    -
    19059 }
    -
    19060 
    -
    19061 VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory(
    -
    19062  VmaAllocator allocator,
    -
    19063  VmaAllocation allocation)
    -
    19064 {
    -
    19065  VMA_ASSERT(allocator && allocation);
    -
    19066 
    -
    19067  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19068 
    -
    19069 #if VMA_RECORDING_ENABLED
    -
    19070  if(allocator->GetRecorder() != VMA_NULL)
    -
    19071  {
    -
    19072  allocator->GetRecorder()->RecordUnmapMemory(
    -
    19073  allocator->GetCurrentFrameIndex(),
    -
    19074  allocation);
    -
    19075  }
    -
    19076 #endif
    -
    19077 
    -
    19078  allocator->Unmap(allocation);
    -
    19079 }
    -
    19080 
    -
    19081 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    -
    19082 {
    -
    19083  VMA_ASSERT(allocator && allocation);
    -
    19084 
    -
    19085  VMA_DEBUG_LOG("vmaFlushAllocation");
    -
    19086 
    -
    19087  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19088 
    -
    19089  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH);
    -
    19090 
    -
    19091 #if VMA_RECORDING_ENABLED
    -
    19092  if(allocator->GetRecorder() != VMA_NULL)
    -
    19093  {
    -
    19094  allocator->GetRecorder()->RecordFlushAllocation(
    -
    19095  allocator->GetCurrentFrameIndex(),
    -
    19096  allocation, offset, size);
    -
    19097  }
    -
    19098 #endif
    +
    19018  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19019 
    +
    19020  allocation->SetUserData(allocator, pUserData);
    +
    19021 
    +
    19022 #if VMA_RECORDING_ENABLED
    +
    19023  if(allocator->GetRecorder() != VMA_NULL)
    +
    19024  {
    +
    19025  allocator->GetRecorder()->RecordSetAllocationUserData(
    +
    19026  allocator->GetCurrentFrameIndex(),
    +
    19027  allocation,
    +
    19028  pUserData);
    +
    19029  }
    +
    19030 #endif
    +
    19031 }
    +
    19032 
    +
    19033 VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation(
    +
    19034  VmaAllocator allocator,
    +
    19035  VmaAllocation* pAllocation)
    +
    19036 {
    +
    19037  VMA_ASSERT(allocator && pAllocation);
    +
    19038 
    +
    19039  VMA_DEBUG_GLOBAL_MUTEX_LOCK;
    +
    19040 
    +
    19041  allocator->CreateLostAllocation(pAllocation);
    +
    19042 
    +
    19043 #if VMA_RECORDING_ENABLED
    +
    19044  if(allocator->GetRecorder() != VMA_NULL)
    +
    19045  {
    +
    19046  allocator->GetRecorder()->RecordCreateLostAllocation(
    +
    19047  allocator->GetCurrentFrameIndex(),
    +
    19048  *pAllocation);
    +
    19049  }
    +
    19050 #endif
    +
    19051 }
    +
    19052 
    +
    19053 VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory(
    +
    19054  VmaAllocator allocator,
    +
    19055  VmaAllocation allocation,
    +
    19056  void** ppData)
    +
    19057 {
    +
    19058  VMA_ASSERT(allocator && allocation && ppData);
    +
    19059 
    +
    19060  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19061 
    +
    19062  VkResult res = allocator->Map(allocation, ppData);
    +
    19063 
    +
    19064 #if VMA_RECORDING_ENABLED
    +
    19065  if(allocator->GetRecorder() != VMA_NULL)
    +
    19066  {
    +
    19067  allocator->GetRecorder()->RecordMapMemory(
    +
    19068  allocator->GetCurrentFrameIndex(),
    +
    19069  allocation);
    +
    19070  }
    +
    19071 #endif
    +
    19072 
    +
    19073  return res;
    +
    19074 }
    +
    19075 
    +
    19076 VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory(
    +
    19077  VmaAllocator allocator,
    +
    19078  VmaAllocation allocation)
    +
    19079 {
    +
    19080  VMA_ASSERT(allocator && allocation);
    +
    19081 
    +
    19082  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19083 
    +
    19084 #if VMA_RECORDING_ENABLED
    +
    19085  if(allocator->GetRecorder() != VMA_NULL)
    +
    19086  {
    +
    19087  allocator->GetRecorder()->RecordUnmapMemory(
    +
    19088  allocator->GetCurrentFrameIndex(),
    +
    19089  allocation);
    +
    19090  }
    +
    19091 #endif
    +
    19092 
    +
    19093  allocator->Unmap(allocation);
    +
    19094 }
    +
    19095 
    +
    19096 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    +
    19097 {
    +
    19098  VMA_ASSERT(allocator && allocation);
    19099 
    -
    19100  return res;
    -
    19101 }
    -
    19102 
    -
    19103 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    -
    19104 {
    -
    19105  VMA_ASSERT(allocator && allocation);
    -
    19106 
    -
    19107  VMA_DEBUG_LOG("vmaInvalidateAllocation");
    -
    19108 
    -
    19109  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19110 
    -
    19111  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
    -
    19112 
    -
    19113 #if VMA_RECORDING_ENABLED
    -
    19114  if(allocator->GetRecorder() != VMA_NULL)
    -
    19115  {
    -
    19116  allocator->GetRecorder()->RecordInvalidateAllocation(
    -
    19117  allocator->GetCurrentFrameIndex(),
    -
    19118  allocation, offset, size);
    -
    19119  }
    -
    19120 #endif
    +
    19100  VMA_DEBUG_LOG("vmaFlushAllocation");
    +
    19101 
    +
    19102  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19103 
    +
    19104  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH);
    +
    19105 
    +
    19106 #if VMA_RECORDING_ENABLED
    +
    19107  if(allocator->GetRecorder() != VMA_NULL)
    +
    19108  {
    +
    19109  allocator->GetRecorder()->RecordFlushAllocation(
    +
    19110  allocator->GetCurrentFrameIndex(),
    +
    19111  allocation, offset, size);
    +
    19112  }
    +
    19113 #endif
    +
    19114 
    +
    19115  return res;
    +
    19116 }
    +
    19117 
    +
    19118 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
    +
    19119 {
    +
    19120  VMA_ASSERT(allocator && allocation);
    19121 
    -
    19122  return res;
    -
    19123 }
    -
    19124 
    -
    19125 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
    -
    19126  VmaAllocator allocator,
    -
    19127  uint32_t allocationCount,
    -
    19128  const VmaAllocation* allocations,
    -
    19129  const VkDeviceSize* offsets,
    -
    19130  const VkDeviceSize* sizes)
    -
    19131 {
    -
    19132  VMA_ASSERT(allocator);
    -
    19133 
    -
    19134  if(allocationCount == 0)
    -
    19135  {
    -
    19136  return VK_SUCCESS;
    -
    19137  }
    -
    19138 
    -
    19139  VMA_ASSERT(allocations);
    -
    19140 
    -
    19141  VMA_DEBUG_LOG("vmaFlushAllocations");
    -
    19142 
    -
    19143  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19144 
    -
    19145  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH);
    -
    19146 
    -
    19147 #if VMA_RECORDING_ENABLED
    -
    19148  if(allocator->GetRecorder() != VMA_NULL)
    -
    19149  {
    -
    19150  //TODO
    -
    19151  }
    -
    19152 #endif
    +
    19122  VMA_DEBUG_LOG("vmaInvalidateAllocation");
    +
    19123 
    +
    19124  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19125 
    +
    19126  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
    +
    19127 
    +
    19128 #if VMA_RECORDING_ENABLED
    +
    19129  if(allocator->GetRecorder() != VMA_NULL)
    +
    19130  {
    +
    19131  allocator->GetRecorder()->RecordInvalidateAllocation(
    +
    19132  allocator->GetCurrentFrameIndex(),
    +
    19133  allocation, offset, size);
    +
    19134  }
    +
    19135 #endif
    +
    19136 
    +
    19137  return res;
    +
    19138 }
    +
    19139 
    +
    19140 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
    +
    19141  VmaAllocator allocator,
    +
    19142  uint32_t allocationCount,
    +
    19143  const VmaAllocation* allocations,
    +
    19144  const VkDeviceSize* offsets,
    +
    19145  const VkDeviceSize* sizes)
    +
    19146 {
    +
    19147  VMA_ASSERT(allocator);
    +
    19148 
    +
    19149  if(allocationCount == 0)
    +
    19150  {
    +
    19151  return VK_SUCCESS;
    +
    19152  }
    19153 
    -
    19154  return res;
    -
    19155 }
    -
    19156 
    -
    19157 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
    -
    19158  VmaAllocator allocator,
    -
    19159  uint32_t allocationCount,
    -
    19160  const VmaAllocation* allocations,
    -
    19161  const VkDeviceSize* offsets,
    -
    19162  const VkDeviceSize* sizes)
    -
    19163 {
    -
    19164  VMA_ASSERT(allocator);
    -
    19165 
    -
    19166  if(allocationCount == 0)
    -
    19167  {
    -
    19168  return VK_SUCCESS;
    -
    19169  }
    -
    19170 
    -
    19171  VMA_ASSERT(allocations);
    -
    19172 
    -
    19173  VMA_DEBUG_LOG("vmaInvalidateAllocations");
    -
    19174 
    -
    19175  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19176 
    -
    19177  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE);
    -
    19178 
    -
    19179 #if VMA_RECORDING_ENABLED
    -
    19180  if(allocator->GetRecorder() != VMA_NULL)
    -
    19181  {
    -
    19182  //TODO
    -
    19183  }
    -
    19184 #endif
    +
    19154  VMA_ASSERT(allocations);
    +
    19155 
    +
    19156  VMA_DEBUG_LOG("vmaFlushAllocations");
    +
    19157 
    +
    19158  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19159 
    +
    19160  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH);
    +
    19161 
    +
    19162 #if VMA_RECORDING_ENABLED
    +
    19163  if(allocator->GetRecorder() != VMA_NULL)
    +
    19164  {
    +
    19165  //TODO
    +
    19166  }
    +
    19167 #endif
    +
    19168 
    +
    19169  return res;
    +
    19170 }
    +
    19171 
    +
    19172 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
    +
    19173  VmaAllocator allocator,
    +
    19174  uint32_t allocationCount,
    +
    19175  const VmaAllocation* allocations,
    +
    19176  const VkDeviceSize* offsets,
    +
    19177  const VkDeviceSize* sizes)
    +
    19178 {
    +
    19179  VMA_ASSERT(allocator);
    +
    19180 
    +
    19181  if(allocationCount == 0)
    +
    19182  {
    +
    19183  return VK_SUCCESS;
    +
    19184  }
    19185 
    -
    19186  return res;
    -
    19187 }
    -
    19188 
    -
    19189 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits)
    -
    19190 {
    -
    19191  VMA_ASSERT(allocator);
    -
    19192 
    -
    19193  VMA_DEBUG_LOG("vmaCheckCorruption");
    -
    19194 
    -
    19195  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19196 
    -
    19197  return allocator->CheckCorruption(memoryTypeBits);
    -
    19198 }
    -
    19199 
    -
    19200 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment(
    -
    19201  VmaAllocator allocator,
    -
    19202  const VmaAllocation* pAllocations,
    -
    19203  size_t allocationCount,
    -
    19204  VkBool32* pAllocationsChanged,
    -
    19205  const VmaDefragmentationInfo *pDefragmentationInfo,
    -
    19206  VmaDefragmentationStats* pDefragmentationStats)
    -
    19207 {
    -
    19208  // Deprecated interface, reimplemented using new one.
    +
    19186  VMA_ASSERT(allocations);
    +
    19187 
    +
    19188  VMA_DEBUG_LOG("vmaInvalidateAllocations");
    +
    19189 
    +
    19190  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19191 
    +
    19192  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE);
    +
    19193 
    +
    19194 #if VMA_RECORDING_ENABLED
    +
    19195  if(allocator->GetRecorder() != VMA_NULL)
    +
    19196  {
    +
    19197  //TODO
    +
    19198  }
    +
    19199 #endif
    +
    19200 
    +
    19201  return res;
    +
    19202 }
    +
    19203 
    +
    19204 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits)
    +
    19205 {
    +
    19206  VMA_ASSERT(allocator);
    +
    19207 
    +
    19208  VMA_DEBUG_LOG("vmaCheckCorruption");
    19209 
    -
    19210  VmaDefragmentationInfo2 info2 = {};
    -
    19211  info2.allocationCount = (uint32_t)allocationCount;
    -
    19212  info2.pAllocations = pAllocations;
    -
    19213  info2.pAllocationsChanged = pAllocationsChanged;
    -
    19214  if(pDefragmentationInfo != VMA_NULL)
    -
    19215  {
    -
    19216  info2.maxCpuAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
    -
    19217  info2.maxCpuBytesToMove = pDefragmentationInfo->maxBytesToMove;
    -
    19218  }
    -
    19219  else
    -
    19220  {
    -
    19221  info2.maxCpuAllocationsToMove = UINT32_MAX;
    -
    19222  info2.maxCpuBytesToMove = VK_WHOLE_SIZE;
    -
    19223  }
    -
    19224  // info2.flags, maxGpuAllocationsToMove, maxGpuBytesToMove, commandBuffer deliberately left zero.
    -
    19225 
    -
    19226  VmaDefragmentationContext ctx;
    -
    19227  VkResult res = vmaDefragmentationBegin(allocator, &info2, pDefragmentationStats, &ctx);
    -
    19228  if(res == VK_NOT_READY)
    -
    19229  {
    -
    19230  res = vmaDefragmentationEnd( allocator, ctx);
    -
    19231  }
    -
    19232  return res;
    -
    19233 }
    -
    19234 
    -
    19235 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin(
    -
    19236  VmaAllocator allocator,
    -
    19237  const VmaDefragmentationInfo2* pInfo,
    -
    19238  VmaDefragmentationStats* pStats,
    -
    19239  VmaDefragmentationContext *pContext)
    -
    19240 {
    -
    19241  VMA_ASSERT(allocator && pInfo && pContext);
    -
    19242 
    -
    19243  // Degenerate case: Nothing to defragment.
    -
    19244  if(pInfo->allocationCount == 0 && pInfo->poolCount == 0)
    -
    19245  {
    -
    19246  return VK_SUCCESS;
    -
    19247  }
    -
    19248 
    -
    19249  VMA_ASSERT(pInfo->allocationCount == 0 || pInfo->pAllocations != VMA_NULL);
    -
    19250  VMA_ASSERT(pInfo->poolCount == 0 || pInfo->pPools != VMA_NULL);
    -
    19251  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->allocationCount, pInfo->pAllocations));
    -
    19252  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->poolCount, pInfo->pPools));
    -
    19253 
    -
    19254  VMA_DEBUG_LOG("vmaDefragmentationBegin");
    -
    19255 
    -
    19256  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19210  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19211 
    +
    19212  return allocator->CheckCorruption(memoryTypeBits);
    +
    19213 }
    +
    19214 
    +
    19215 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment(
    +
    19216  VmaAllocator allocator,
    +
    19217  const VmaAllocation* pAllocations,
    +
    19218  size_t allocationCount,
    +
    19219  VkBool32* pAllocationsChanged,
    +
    19220  const VmaDefragmentationInfo *pDefragmentationInfo,
    +
    19221  VmaDefragmentationStats* pDefragmentationStats)
    +
    19222 {
    +
    19223  // Deprecated interface, reimplemented using new one.
    +
    19224 
    +
    19225  VmaDefragmentationInfo2 info2 = {};
    +
    19226  info2.allocationCount = (uint32_t)allocationCount;
    +
    19227  info2.pAllocations = pAllocations;
    +
    19228  info2.pAllocationsChanged = pAllocationsChanged;
    +
    19229  if(pDefragmentationInfo != VMA_NULL)
    +
    19230  {
    +
    19231  info2.maxCpuAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
    +
    19232  info2.maxCpuBytesToMove = pDefragmentationInfo->maxBytesToMove;
    +
    19233  }
    +
    19234  else
    +
    19235  {
    +
    19236  info2.maxCpuAllocationsToMove = UINT32_MAX;
    +
    19237  info2.maxCpuBytesToMove = VK_WHOLE_SIZE;
    +
    19238  }
    +
    19239  // info2.flags, maxGpuAllocationsToMove, maxGpuBytesToMove, commandBuffer deliberately left zero.
    +
    19240 
    +
    19241  VmaDefragmentationContext ctx;
    +
    19242  VkResult res = vmaDefragmentationBegin(allocator, &info2, pDefragmentationStats, &ctx);
    +
    19243  if(res == VK_NOT_READY)
    +
    19244  {
    +
    19245  res = vmaDefragmentationEnd( allocator, ctx);
    +
    19246  }
    +
    19247  return res;
    +
    19248 }
    +
    19249 
    +
    19250 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin(
    +
    19251  VmaAllocator allocator,
    +
    19252  const VmaDefragmentationInfo2* pInfo,
    +
    19253  VmaDefragmentationStats* pStats,
    +
    19254  VmaDefragmentationContext *pContext)
    +
    19255 {
    +
    19256  VMA_ASSERT(allocator && pInfo && pContext);
    19257 
    -
    19258  VkResult res = allocator->DefragmentationBegin(*pInfo, pStats, pContext);
    -
    19259 
    -
    19260 #if VMA_RECORDING_ENABLED
    -
    19261  if(allocator->GetRecorder() != VMA_NULL)
    -
    19262  {
    -
    19263  allocator->GetRecorder()->RecordDefragmentationBegin(
    -
    19264  allocator->GetCurrentFrameIndex(), *pInfo, *pContext);
    -
    19265  }
    -
    19266 #endif
    -
    19267 
    -
    19268  return res;
    -
    19269 }
    +
    19258  // Degenerate case: Nothing to defragment.
    +
    19259  if(pInfo->allocationCount == 0 && pInfo->poolCount == 0)
    +
    19260  {
    +
    19261  return VK_SUCCESS;
    +
    19262  }
    +
    19263 
    +
    19264  VMA_ASSERT(pInfo->allocationCount == 0 || pInfo->pAllocations != VMA_NULL);
    +
    19265  VMA_ASSERT(pInfo->poolCount == 0 || pInfo->pPools != VMA_NULL);
    +
    19266  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->allocationCount, pInfo->pAllocations));
    +
    19267  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->poolCount, pInfo->pPools));
    +
    19268 
    +
    19269  VMA_DEBUG_LOG("vmaDefragmentationBegin");
    19270 
    -
    19271 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd(
    -
    19272  VmaAllocator allocator,
    -
    19273  VmaDefragmentationContext context)
    -
    19274 {
    -
    19275  VMA_ASSERT(allocator);
    -
    19276 
    -
    19277  VMA_DEBUG_LOG("vmaDefragmentationEnd");
    -
    19278 
    -
    19279  if(context != VK_NULL_HANDLE)
    -
    19280  {
    -
    19281  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19271  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19272 
    +
    19273  VkResult res = allocator->DefragmentationBegin(*pInfo, pStats, pContext);
    +
    19274 
    +
    19275 #if VMA_RECORDING_ENABLED
    +
    19276  if(allocator->GetRecorder() != VMA_NULL)
    +
    19277  {
    +
    19278  allocator->GetRecorder()->RecordDefragmentationBegin(
    +
    19279  allocator->GetCurrentFrameIndex(), *pInfo, *pContext);
    +
    19280  }
    +
    19281 #endif
    19282 
    -
    19283 #if VMA_RECORDING_ENABLED
    -
    19284  if(allocator->GetRecorder() != VMA_NULL)
    -
    19285  {
    -
    19286  allocator->GetRecorder()->RecordDefragmentationEnd(
    -
    19287  allocator->GetCurrentFrameIndex(), context);
    -
    19288  }
    -
    19289 #endif
    -
    19290 
    -
    19291  return allocator->DefragmentationEnd(context);
    -
    19292  }
    -
    19293  else
    -
    19294  {
    -
    19295  return VK_SUCCESS;
    -
    19296  }
    -
    19297 }
    -
    19298 
    -
    19299 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass(
    -
    19300  VmaAllocator allocator,
    -
    19301  VmaDefragmentationContext context,
    -
    19302  VmaDefragmentationPassInfo* pInfo
    -
    19303  )
    -
    19304 {
    -
    19305  VMA_ASSERT(allocator);
    -
    19306  VMA_ASSERT(pInfo);
    -
    19307 
    -
    19308  VMA_DEBUG_LOG("vmaBeginDefragmentationPass");
    -
    19309 
    -
    19310  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19311 
    -
    19312  if(context == VK_NULL_HANDLE)
    -
    19313  {
    -
    19314  pInfo->moveCount = 0;
    -
    19315  return VK_SUCCESS;
    -
    19316  }
    -
    19317 
    -
    19318  return allocator->DefragmentationPassBegin(pInfo, context);
    -
    19319 }
    -
    19320 VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass(
    -
    19321  VmaAllocator allocator,
    -
    19322  VmaDefragmentationContext context)
    -
    19323 {
    -
    19324  VMA_ASSERT(allocator);
    -
    19325 
    -
    19326  VMA_DEBUG_LOG("vmaEndDefragmentationPass");
    -
    19327  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19328 
    -
    19329  if(context == VK_NULL_HANDLE)
    +
    19283  return res;
    +
    19284 }
    +
    19285 
    +
    19286 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd(
    +
    19287  VmaAllocator allocator,
    +
    19288  VmaDefragmentationContext context)
    +
    19289 {
    +
    19290  VMA_ASSERT(allocator);
    +
    19291 
    +
    19292  VMA_DEBUG_LOG("vmaDefragmentationEnd");
    +
    19293 
    +
    19294  if(context != VK_NULL_HANDLE)
    +
    19295  {
    +
    19296  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19297 
    +
    19298 #if VMA_RECORDING_ENABLED
    +
    19299  if(allocator->GetRecorder() != VMA_NULL)
    +
    19300  {
    +
    19301  allocator->GetRecorder()->RecordDefragmentationEnd(
    +
    19302  allocator->GetCurrentFrameIndex(), context);
    +
    19303  }
    +
    19304 #endif
    +
    19305 
    +
    19306  return allocator->DefragmentationEnd(context);
    +
    19307  }
    +
    19308  else
    +
    19309  {
    +
    19310  return VK_SUCCESS;
    +
    19311  }
    +
    19312 }
    +
    19313 
    +
    19314 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass(
    +
    19315  VmaAllocator allocator,
    +
    19316  VmaDefragmentationContext context,
    +
    19317  VmaDefragmentationPassInfo* pInfo
    +
    19318  )
    +
    19319 {
    +
    19320  VMA_ASSERT(allocator);
    +
    19321  VMA_ASSERT(pInfo);
    +
    19322 
    +
    19323  VMA_DEBUG_LOG("vmaBeginDefragmentationPass");
    +
    19324 
    +
    19325  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19326 
    +
    19327  if(context == VK_NULL_HANDLE)
    +
    19328  {
    +
    19329  pInfo->moveCount = 0;
    19330  return VK_SUCCESS;
    -
    19331 
    -
    19332  return allocator->DefragmentationPassEnd(context);
    -
    19333 }
    -
    19334 
    -
    19335 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory(
    +
    19331  }
    +
    19332 
    +
    19333  return allocator->DefragmentationPassBegin(pInfo, context);
    +
    19334 }
    +
    19335 VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass(
    19336  VmaAllocator allocator,
    -
    19337  VmaAllocation allocation,
    -
    19338  VkBuffer buffer)
    -
    19339 {
    -
    19340  VMA_ASSERT(allocator && allocation && buffer);
    -
    19341 
    -
    19342  VMA_DEBUG_LOG("vmaBindBufferMemory");
    +
    19337  VmaDefragmentationContext context)
    +
    19338 {
    +
    19339  VMA_ASSERT(allocator);
    +
    19340 
    +
    19341  VMA_DEBUG_LOG("vmaEndDefragmentationPass");
    +
    19342  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    19343 
    -
    19344  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19345 
    -
    19346  return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL);
    -
    19347 }
    -
    19348 
    -
    19349 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2(
    -
    19350  VmaAllocator allocator,
    -
    19351  VmaAllocation allocation,
    -
    19352  VkDeviceSize allocationLocalOffset,
    -
    19353  VkBuffer buffer,
    -
    19354  const void* pNext)
    -
    19355 {
    -
    19356  VMA_ASSERT(allocator && allocation && buffer);
    -
    19357 
    -
    19358  VMA_DEBUG_LOG("vmaBindBufferMemory2");
    -
    19359 
    -
    19360  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19361 
    -
    19362  return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext);
    -
    19363 }
    -
    19364 
    -
    19365 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory(
    -
    19366  VmaAllocator allocator,
    -
    19367  VmaAllocation allocation,
    -
    19368  VkImage image)
    -
    19369 {
    -
    19370  VMA_ASSERT(allocator && allocation && image);
    -
    19371 
    -
    19372  VMA_DEBUG_LOG("vmaBindImageMemory");
    -
    19373 
    -
    19374  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19375 
    -
    19376  return allocator->BindImageMemory(allocation, 0, image, VMA_NULL);
    -
    19377 }
    -
    19378 
    -
    19379 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2(
    -
    19380  VmaAllocator allocator,
    -
    19381  VmaAllocation allocation,
    -
    19382  VkDeviceSize allocationLocalOffset,
    -
    19383  VkImage image,
    -
    19384  const void* pNext)
    -
    19385 {
    -
    19386  VMA_ASSERT(allocator && allocation && image);
    -
    19387 
    -
    19388  VMA_DEBUG_LOG("vmaBindImageMemory2");
    -
    19389 
    -
    19390  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19391 
    -
    19392  return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext);
    -
    19393 }
    -
    19394 
    -
    19395 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer(
    -
    19396  VmaAllocator allocator,
    -
    19397  const VkBufferCreateInfo* pBufferCreateInfo,
    -
    19398  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    -
    19399  VkBuffer* pBuffer,
    -
    19400  VmaAllocation* pAllocation,
    -
    19401  VmaAllocationInfo* pAllocationInfo)
    -
    19402 {
    -
    19403  VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
    +
    19344  if(context == VK_NULL_HANDLE)
    +
    19345  return VK_SUCCESS;
    +
    19346 
    +
    19347  return allocator->DefragmentationPassEnd(context);
    +
    19348 }
    +
    19349 
    +
    19350 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory(
    +
    19351  VmaAllocator allocator,
    +
    19352  VmaAllocation allocation,
    +
    19353  VkBuffer buffer)
    +
    19354 {
    +
    19355  VMA_ASSERT(allocator && allocation && buffer);
    +
    19356 
    +
    19357  VMA_DEBUG_LOG("vmaBindBufferMemory");
    +
    19358 
    +
    19359  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19360 
    +
    19361  return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL);
    +
    19362 }
    +
    19363 
    +
    19364 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2(
    +
    19365  VmaAllocator allocator,
    +
    19366  VmaAllocation allocation,
    +
    19367  VkDeviceSize allocationLocalOffset,
    +
    19368  VkBuffer buffer,
    +
    19369  const void* pNext)
    +
    19370 {
    +
    19371  VMA_ASSERT(allocator && allocation && buffer);
    +
    19372 
    +
    19373  VMA_DEBUG_LOG("vmaBindBufferMemory2");
    +
    19374 
    +
    19375  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19376 
    +
    19377  return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext);
    +
    19378 }
    +
    19379 
    +
    19380 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory(
    +
    19381  VmaAllocator allocator,
    +
    19382  VmaAllocation allocation,
    +
    19383  VkImage image)
    +
    19384 {
    +
    19385  VMA_ASSERT(allocator && allocation && image);
    +
    19386 
    +
    19387  VMA_DEBUG_LOG("vmaBindImageMemory");
    +
    19388 
    +
    19389  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19390 
    +
    19391  return allocator->BindImageMemory(allocation, 0, image, VMA_NULL);
    +
    19392 }
    +
    19393 
    +
    19394 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2(
    +
    19395  VmaAllocator allocator,
    +
    19396  VmaAllocation allocation,
    +
    19397  VkDeviceSize allocationLocalOffset,
    +
    19398  VkImage image,
    +
    19399  const void* pNext)
    +
    19400 {
    +
    19401  VMA_ASSERT(allocator && allocation && image);
    +
    19402 
    +
    19403  VMA_DEBUG_LOG("vmaBindImageMemory2");
    19404 
    -
    19405  if(pBufferCreateInfo->size == 0)
    -
    19406  {
    -
    19407  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    19408  }
    -
    19409  if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 &&
    -
    19410  !allocator->m_UseKhrBufferDeviceAddress)
    -
    19411  {
    -
    19412  VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used.");
    -
    19413  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    19414  }
    -
    19415 
    -
    19416  VMA_DEBUG_LOG("vmaCreateBuffer");
    -
    19417 
    -
    19418  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19405  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19406 
    +
    19407  return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext);
    +
    19408 }
    +
    19409 
    +
    19410 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer(
    +
    19411  VmaAllocator allocator,
    +
    19412  const VkBufferCreateInfo* pBufferCreateInfo,
    +
    19413  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    +
    19414  VkBuffer* pBuffer,
    +
    19415  VmaAllocation* pAllocation,
    +
    19416  VmaAllocationInfo* pAllocationInfo)
    +
    19417 {
    +
    19418  VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
    19419 
    -
    19420  *pBuffer = VK_NULL_HANDLE;
    -
    19421  *pAllocation = VK_NULL_HANDLE;
    -
    19422 
    -
    19423  // 1. Create VkBuffer.
    -
    19424  VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
    -
    19425  allocator->m_hDevice,
    -
    19426  pBufferCreateInfo,
    -
    19427  allocator->GetAllocationCallbacks(),
    -
    19428  pBuffer);
    -
    19429  if(res >= 0)
    -
    19430  {
    -
    19431  // 2. vkGetBufferMemoryRequirements.
    -
    19432  VkMemoryRequirements vkMemReq = {};
    -
    19433  bool requiresDedicatedAllocation = false;
    -
    19434  bool prefersDedicatedAllocation = false;
    -
    19435  allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
    -
    19436  requiresDedicatedAllocation, prefersDedicatedAllocation);
    +
    19420  if(pBufferCreateInfo->size == 0)
    +
    19421  {
    +
    19422  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    19423  }
    +
    19424  if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 &&
    +
    19425  !allocator->m_UseKhrBufferDeviceAddress)
    +
    19426  {
    +
    19427  VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used.");
    +
    19428  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    19429  }
    +
    19430 
    +
    19431  VMA_DEBUG_LOG("vmaCreateBuffer");
    +
    19432 
    +
    19433  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19434 
    +
    19435  *pBuffer = VK_NULL_HANDLE;
    +
    19436  *pAllocation = VK_NULL_HANDLE;
    19437 
    -
    19438  // 3. Allocate memory using allocator.
    -
    19439  res = allocator->AllocateMemory(
    -
    19440  vkMemReq,
    -
    19441  requiresDedicatedAllocation,
    -
    19442  prefersDedicatedAllocation,
    -
    19443  *pBuffer, // dedicatedBuffer
    -
    19444  pBufferCreateInfo->usage, // dedicatedBufferUsage
    -
    19445  VK_NULL_HANDLE, // dedicatedImage
    -
    19446  *pAllocationCreateInfo,
    -
    19447  VMA_SUBALLOCATION_TYPE_BUFFER,
    -
    19448  1, // allocationCount
    -
    19449  pAllocation);
    -
    19450 
    -
    19451 #if VMA_RECORDING_ENABLED
    -
    19452  if(allocator->GetRecorder() != VMA_NULL)
    -
    19453  {
    -
    19454  allocator->GetRecorder()->RecordCreateBuffer(
    -
    19455  allocator->GetCurrentFrameIndex(),
    -
    19456  *pBufferCreateInfo,
    -
    19457  *pAllocationCreateInfo,
    -
    19458  *pAllocation);
    -
    19459  }
    -
    19460 #endif
    -
    19461 
    -
    19462  if(res >= 0)
    -
    19463  {
    -
    19464  // 3. Bind buffer with memory.
    -
    19465  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
    -
    19466  {
    -
    19467  res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL);
    -
    19468  }
    -
    19469  if(res >= 0)
    -
    19470  {
    -
    19471  // All steps succeeded.
    -
    19472  #if VMA_STATS_STRING_ENABLED
    -
    19473  (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage);
    -
    19474  #endif
    -
    19475  if(pAllocationInfo != VMA_NULL)
    -
    19476  {
    -
    19477  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    -
    19478  }
    -
    19479 
    -
    19480  return VK_SUCCESS;
    -
    19481  }
    -
    19482  allocator->FreeMemory(
    -
    19483  1, // allocationCount
    -
    19484  pAllocation);
    -
    19485  *pAllocation = VK_NULL_HANDLE;
    -
    19486  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    -
    19487  *pBuffer = VK_NULL_HANDLE;
    -
    19488  return res;
    -
    19489  }
    -
    19490  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    -
    19491  *pBuffer = VK_NULL_HANDLE;
    -
    19492  return res;
    -
    19493  }
    -
    19494  return res;
    -
    19495 }
    -
    19496 
    -
    19497 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
    -
    19498  VmaAllocator allocator,
    -
    19499  VkBuffer buffer,
    -
    19500  VmaAllocation allocation)
    -
    19501 {
    -
    19502  VMA_ASSERT(allocator);
    -
    19503 
    -
    19504  if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
    -
    19505  {
    -
    19506  return;
    -
    19507  }
    -
    19508 
    -
    19509  VMA_DEBUG_LOG("vmaDestroyBuffer");
    -
    19510 
    -
    19511  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19512 
    -
    19513 #if VMA_RECORDING_ENABLED
    -
    19514  if(allocator->GetRecorder() != VMA_NULL)
    -
    19515  {
    -
    19516  allocator->GetRecorder()->RecordDestroyBuffer(
    -
    19517  allocator->GetCurrentFrameIndex(),
    -
    19518  allocation);
    -
    19519  }
    -
    19520 #endif
    -
    19521 
    -
    19522  if(buffer != VK_NULL_HANDLE)
    -
    19523  {
    -
    19524  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
    -
    19525  }
    -
    19526 
    -
    19527  if(allocation != VK_NULL_HANDLE)
    -
    19528  {
    -
    19529  allocator->FreeMemory(
    -
    19530  1, // allocationCount
    -
    19531  &allocation);
    +
    19438  // 1. Create VkBuffer.
    +
    19439  VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
    +
    19440  allocator->m_hDevice,
    +
    19441  pBufferCreateInfo,
    +
    19442  allocator->GetAllocationCallbacks(),
    +
    19443  pBuffer);
    +
    19444  if(res >= 0)
    +
    19445  {
    +
    19446  // 2. vkGetBufferMemoryRequirements.
    +
    19447  VkMemoryRequirements vkMemReq = {};
    +
    19448  bool requiresDedicatedAllocation = false;
    +
    19449  bool prefersDedicatedAllocation = false;
    +
    19450  allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
    +
    19451  requiresDedicatedAllocation, prefersDedicatedAllocation);
    +
    19452 
    +
    19453  // 3. Allocate memory using allocator.
    +
    19454  res = allocator->AllocateMemory(
    +
    19455  vkMemReq,
    +
    19456  requiresDedicatedAllocation,
    +
    19457  prefersDedicatedAllocation,
    +
    19458  *pBuffer, // dedicatedBuffer
    +
    19459  pBufferCreateInfo->usage, // dedicatedBufferUsage
    +
    19460  VK_NULL_HANDLE, // dedicatedImage
    +
    19461  *pAllocationCreateInfo,
    +
    19462  VMA_SUBALLOCATION_TYPE_BUFFER,
    +
    19463  1, // allocationCount
    +
    19464  pAllocation);
    +
    19465 
    +
    19466 #if VMA_RECORDING_ENABLED
    +
    19467  if(allocator->GetRecorder() != VMA_NULL)
    +
    19468  {
    +
    19469  allocator->GetRecorder()->RecordCreateBuffer(
    +
    19470  allocator->GetCurrentFrameIndex(),
    +
    19471  *pBufferCreateInfo,
    +
    19472  *pAllocationCreateInfo,
    +
    19473  *pAllocation);
    +
    19474  }
    +
    19475 #endif
    +
    19476 
    +
    19477  if(res >= 0)
    +
    19478  {
    +
    19479  // 3. Bind buffer with memory.
    +
    19480  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
    +
    19481  {
    +
    19482  res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL);
    +
    19483  }
    +
    19484  if(res >= 0)
    +
    19485  {
    +
    19486  // All steps succeeded.
    +
    19487  #if VMA_STATS_STRING_ENABLED
    +
    19488  (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage);
    +
    19489  #endif
    +
    19490  if(pAllocationInfo != VMA_NULL)
    +
    19491  {
    +
    19492  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    +
    19493  }
    +
    19494 
    +
    19495  return VK_SUCCESS;
    +
    19496  }
    +
    19497  allocator->FreeMemory(
    +
    19498  1, // allocationCount
    +
    19499  pAllocation);
    +
    19500  *pAllocation = VK_NULL_HANDLE;
    +
    19501  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    +
    19502  *pBuffer = VK_NULL_HANDLE;
    +
    19503  return res;
    +
    19504  }
    +
    19505  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    +
    19506  *pBuffer = VK_NULL_HANDLE;
    +
    19507  return res;
    +
    19508  }
    +
    19509  return res;
    +
    19510 }
    +
    19511 
    +
    19512 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment(
    +
    19513  VmaAllocator allocator,
    +
    19514  const VkBufferCreateInfo* pBufferCreateInfo,
    +
    19515  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    +
    19516  VkDeviceSize minAlignment,
    +
    19517  VkBuffer* pBuffer,
    +
    19518  VmaAllocation* pAllocation,
    +
    19519  VmaAllocationInfo* pAllocationInfo)
    +
    19520 {
    +
    19521  VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && VmaIsPow2(minAlignment) && pBuffer && pAllocation);
    +
    19522 
    +
    19523  if(pBufferCreateInfo->size == 0)
    +
    19524  {
    +
    19525  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    19526  }
    +
    19527  if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 &&
    +
    19528  !allocator->m_UseKhrBufferDeviceAddress)
    +
    19529  {
    +
    19530  VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used.");
    +
    19531  return VK_ERROR_VALIDATION_FAILED_EXT;
    19532  }
    -
    19533 }
    -
    19534 
    -
    19535 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
    -
    19536  VmaAllocator allocator,
    -
    19537  const VkImageCreateInfo* pImageCreateInfo,
    -
    19538  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    -
    19539  VkImage* pImage,
    -
    19540  VmaAllocation* pAllocation,
    -
    19541  VmaAllocationInfo* pAllocationInfo)
    -
    19542 {
    -
    19543  VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
    -
    19544 
    -
    19545  if(pImageCreateInfo->extent.width == 0 ||
    -
    19546  pImageCreateInfo->extent.height == 0 ||
    -
    19547  pImageCreateInfo->extent.depth == 0 ||
    -
    19548  pImageCreateInfo->mipLevels == 0 ||
    -
    19549  pImageCreateInfo->arrayLayers == 0)
    -
    19550  {
    -
    19551  return VK_ERROR_VALIDATION_FAILED_EXT;
    -
    19552  }
    -
    19553 
    -
    19554  VMA_DEBUG_LOG("vmaCreateImage");
    +
    19533 
    +
    19534  VMA_DEBUG_LOG("vmaCreateBufferWithAlignment");
    +
    19535 
    +
    19536  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19537 
    +
    19538  *pBuffer = VK_NULL_HANDLE;
    +
    19539  *pAllocation = VK_NULL_HANDLE;
    +
    19540 
    +
    19541  // 1. Create VkBuffer.
    +
    19542  VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
    +
    19543  allocator->m_hDevice,
    +
    19544  pBufferCreateInfo,
    +
    19545  allocator->GetAllocationCallbacks(),
    +
    19546  pBuffer);
    +
    19547  if(res >= 0)
    +
    19548  {
    +
    19549  // 2. vkGetBufferMemoryRequirements.
    +
    19550  VkMemoryRequirements vkMemReq = {};
    +
    19551  bool requiresDedicatedAllocation = false;
    +
    19552  bool prefersDedicatedAllocation = false;
    +
    19553  allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
    +
    19554  requiresDedicatedAllocation, prefersDedicatedAllocation);
    19555 
    -
    19556  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19557 
    -
    19558  *pImage = VK_NULL_HANDLE;
    -
    19559  *pAllocation = VK_NULL_HANDLE;
    -
    19560 
    -
    19561  // 1. Create VkImage.
    -
    19562  VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)(
    -
    19563  allocator->m_hDevice,
    -
    19564  pImageCreateInfo,
    -
    19565  allocator->GetAllocationCallbacks(),
    -
    19566  pImage);
    -
    19567  if(res >= 0)
    -
    19568  {
    -
    19569  VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
    -
    19570  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
    -
    19571  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
    -
    19572 
    -
    19573  // 2. Allocate memory using allocator.
    -
    19574  VkMemoryRequirements vkMemReq = {};
    -
    19575  bool requiresDedicatedAllocation = false;
    -
    19576  bool prefersDedicatedAllocation = false;
    -
    19577  allocator->GetImageMemoryRequirements(*pImage, vkMemReq,
    -
    19578  requiresDedicatedAllocation, prefersDedicatedAllocation);
    -
    19579 
    -
    19580  res = allocator->AllocateMemory(
    -
    19581  vkMemReq,
    -
    19582  requiresDedicatedAllocation,
    -
    19583  prefersDedicatedAllocation,
    -
    19584  VK_NULL_HANDLE, // dedicatedBuffer
    -
    19585  UINT32_MAX, // dedicatedBufferUsage
    -
    19586  *pImage, // dedicatedImage
    -
    19587  *pAllocationCreateInfo,
    -
    19588  suballocType,
    -
    19589  1, // allocationCount
    -
    19590  pAllocation);
    -
    19591 
    -
    19592 #if VMA_RECORDING_ENABLED
    -
    19593  if(allocator->GetRecorder() != VMA_NULL)
    -
    19594  {
    -
    19595  allocator->GetRecorder()->RecordCreateImage(
    -
    19596  allocator->GetCurrentFrameIndex(),
    -
    19597  *pImageCreateInfo,
    -
    19598  *pAllocationCreateInfo,
    -
    19599  *pAllocation);
    -
    19600  }
    -
    19601 #endif
    -
    19602 
    -
    19603  if(res >= 0)
    -
    19604  {
    -
    19605  // 3. Bind image with memory.
    -
    19606  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
    -
    19607  {
    -
    19608  res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL);
    -
    19609  }
    -
    19610  if(res >= 0)
    -
    19611  {
    -
    19612  // All steps succeeded.
    -
    19613  #if VMA_STATS_STRING_ENABLED
    -
    19614  (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage);
    -
    19615  #endif
    -
    19616  if(pAllocationInfo != VMA_NULL)
    -
    19617  {
    -
    19618  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    -
    19619  }
    +
    19556  // 2a. Include minAlignment
    +
    19557  vkMemReq.alignment = VMA_MAX(vkMemReq.alignment, minAlignment);
    +
    19558 
    +
    19559  // 3. Allocate memory using allocator.
    +
    19560  res = allocator->AllocateMemory(
    +
    19561  vkMemReq,
    +
    19562  requiresDedicatedAllocation,
    +
    19563  prefersDedicatedAllocation,
    +
    19564  *pBuffer, // dedicatedBuffer
    +
    19565  pBufferCreateInfo->usage, // dedicatedBufferUsage
    +
    19566  VK_NULL_HANDLE, // dedicatedImage
    +
    19567  *pAllocationCreateInfo,
    +
    19568  VMA_SUBALLOCATION_TYPE_BUFFER,
    +
    19569  1, // allocationCount
    +
    19570  pAllocation);
    +
    19571 
    +
    19572 #if VMA_RECORDING_ENABLED
    +
    19573  if(allocator->GetRecorder() != VMA_NULL)
    +
    19574  {
    +
    19575  VMA_ASSERT(0 && "Not implemented.");
    +
    19576  }
    +
    19577 #endif
    +
    19578 
    +
    19579  if(res >= 0)
    +
    19580  {
    +
    19581  // 3. Bind buffer with memory.
    +
    19582  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
    +
    19583  {
    +
    19584  res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL);
    +
    19585  }
    +
    19586  if(res >= 0)
    +
    19587  {
    +
    19588  // All steps succeeded.
    +
    19589  #if VMA_STATS_STRING_ENABLED
    +
    19590  (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage);
    +
    19591  #endif
    +
    19592  if(pAllocationInfo != VMA_NULL)
    +
    19593  {
    +
    19594  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    +
    19595  }
    +
    19596 
    +
    19597  return VK_SUCCESS;
    +
    19598  }
    +
    19599  allocator->FreeMemory(
    +
    19600  1, // allocationCount
    +
    19601  pAllocation);
    +
    19602  *pAllocation = VK_NULL_HANDLE;
    +
    19603  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    +
    19604  *pBuffer = VK_NULL_HANDLE;
    +
    19605  return res;
    +
    19606  }
    +
    19607  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    +
    19608  *pBuffer = VK_NULL_HANDLE;
    +
    19609  return res;
    +
    19610  }
    +
    19611  return res;
    +
    19612 }
    +
    19613 
    +
    19614 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
    +
    19615  VmaAllocator allocator,
    +
    19616  VkBuffer buffer,
    +
    19617  VmaAllocation allocation)
    +
    19618 {
    +
    19619  VMA_ASSERT(allocator);
    19620 
    -
    19621  return VK_SUCCESS;
    -
    19622  }
    -
    19623  allocator->FreeMemory(
    -
    19624  1, // allocationCount
    -
    19625  pAllocation);
    -
    19626  *pAllocation = VK_NULL_HANDLE;
    -
    19627  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
    -
    19628  *pImage = VK_NULL_HANDLE;
    -
    19629  return res;
    -
    19630  }
    -
    19631  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
    -
    19632  *pImage = VK_NULL_HANDLE;
    -
    19633  return res;
    -
    19634  }
    -
    19635  return res;
    -
    19636 }
    -
    19637 
    -
    19638 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
    -
    19639  VmaAllocator allocator,
    -
    19640  VkImage image,
    -
    19641  VmaAllocation allocation)
    -
    19642 {
    -
    19643  VMA_ASSERT(allocator);
    -
    19644 
    -
    19645  if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
    -
    19646  {
    -
    19647  return;
    -
    19648  }
    -
    19649 
    -
    19650  VMA_DEBUG_LOG("vmaDestroyImage");
    +
    19621  if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
    +
    19622  {
    +
    19623  return;
    +
    19624  }
    +
    19625 
    +
    19626  VMA_DEBUG_LOG("vmaDestroyBuffer");
    +
    19627 
    +
    19628  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19629 
    +
    19630 #if VMA_RECORDING_ENABLED
    +
    19631  if(allocator->GetRecorder() != VMA_NULL)
    +
    19632  {
    +
    19633  allocator->GetRecorder()->RecordDestroyBuffer(
    +
    19634  allocator->GetCurrentFrameIndex(),
    +
    19635  allocation);
    +
    19636  }
    +
    19637 #endif
    +
    19638 
    +
    19639  if(buffer != VK_NULL_HANDLE)
    +
    19640  {
    +
    19641  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
    +
    19642  }
    +
    19643 
    +
    19644  if(allocation != VK_NULL_HANDLE)
    +
    19645  {
    +
    19646  allocator->FreeMemory(
    +
    19647  1, // allocationCount
    +
    19648  &allocation);
    +
    19649  }
    +
    19650 }
    19651 
    -
    19652  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    -
    19653 
    -
    19654 #if VMA_RECORDING_ENABLED
    -
    19655  if(allocator->GetRecorder() != VMA_NULL)
    -
    19656  {
    -
    19657  allocator->GetRecorder()->RecordDestroyImage(
    -
    19658  allocator->GetCurrentFrameIndex(),
    -
    19659  allocation);
    -
    19660  }
    -
    19661 #endif
    -
    19662 
    -
    19663  if(image != VK_NULL_HANDLE)
    -
    19664  {
    -
    19665  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
    -
    19666  }
    -
    19667  if(allocation != VK_NULL_HANDLE)
    -
    19668  {
    -
    19669  allocator->FreeMemory(
    -
    19670  1, // allocationCount
    -
    19671  &allocation);
    -
    19672  }
    -
    19673 }
    +
    19652 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
    +
    19653  VmaAllocator allocator,
    +
    19654  const VkImageCreateInfo* pImageCreateInfo,
    +
    19655  const VmaAllocationCreateInfo* pAllocationCreateInfo,
    +
    19656  VkImage* pImage,
    +
    19657  VmaAllocation* pAllocation,
    +
    19658  VmaAllocationInfo* pAllocationInfo)
    +
    19659 {
    +
    19660  VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
    +
    19661 
    +
    19662  if(pImageCreateInfo->extent.width == 0 ||
    +
    19663  pImageCreateInfo->extent.height == 0 ||
    +
    19664  pImageCreateInfo->extent.depth == 0 ||
    +
    19665  pImageCreateInfo->mipLevels == 0 ||
    +
    19666  pImageCreateInfo->arrayLayers == 0)
    +
    19667  {
    +
    19668  return VK_ERROR_VALIDATION_FAILED_EXT;
    +
    19669  }
    +
    19670 
    +
    19671  VMA_DEBUG_LOG("vmaCreateImage");
    +
    19672 
    +
    19673  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    19674 
    -
    19675 #endif // #ifdef VMA_IMPLEMENTATION
    +
    19675  *pImage = VK_NULL_HANDLE;
    +
    19676  *pAllocation = VK_NULL_HANDLE;
    +
    19677 
    +
    19678  // 1. Create VkImage.
    +
    19679  VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)(
    +
    19680  allocator->m_hDevice,
    +
    19681  pImageCreateInfo,
    +
    19682  allocator->GetAllocationCallbacks(),
    +
    19683  pImage);
    +
    19684  if(res >= 0)
    +
    19685  {
    +
    19686  VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
    +
    19687  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
    +
    19688  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
    +
    19689 
    +
    19690  // 2. Allocate memory using allocator.
    +
    19691  VkMemoryRequirements vkMemReq = {};
    +
    19692  bool requiresDedicatedAllocation = false;
    +
    19693  bool prefersDedicatedAllocation = false;
    +
    19694  allocator->GetImageMemoryRequirements(*pImage, vkMemReq,
    +
    19695  requiresDedicatedAllocation, prefersDedicatedAllocation);
    +
    19696 
    +
    19697  res = allocator->AllocateMemory(
    +
    19698  vkMemReq,
    +
    19699  requiresDedicatedAllocation,
    +
    19700  prefersDedicatedAllocation,
    +
    19701  VK_NULL_HANDLE, // dedicatedBuffer
    +
    19702  UINT32_MAX, // dedicatedBufferUsage
    +
    19703  *pImage, // dedicatedImage
    +
    19704  *pAllocationCreateInfo,
    +
    19705  suballocType,
    +
    19706  1, // allocationCount
    +
    19707  pAllocation);
    +
    19708 
    +
    19709 #if VMA_RECORDING_ENABLED
    +
    19710  if(allocator->GetRecorder() != VMA_NULL)
    +
    19711  {
    +
    19712  allocator->GetRecorder()->RecordCreateImage(
    +
    19713  allocator->GetCurrentFrameIndex(),
    +
    19714  *pImageCreateInfo,
    +
    19715  *pAllocationCreateInfo,
    +
    19716  *pAllocation);
    +
    19717  }
    +
    19718 #endif
    +
    19719 
    +
    19720  if(res >= 0)
    +
    19721  {
    +
    19722  // 3. Bind image with memory.
    +
    19723  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
    +
    19724  {
    +
    19725  res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL);
    +
    19726  }
    +
    19727  if(res >= 0)
    +
    19728  {
    +
    19729  // All steps succeeded.
    +
    19730  #if VMA_STATS_STRING_ENABLED
    +
    19731  (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage);
    +
    19732  #endif
    +
    19733  if(pAllocationInfo != VMA_NULL)
    +
    19734  {
    +
    19735  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    +
    19736  }
    +
    19737 
    +
    19738  return VK_SUCCESS;
    +
    19739  }
    +
    19740  allocator->FreeMemory(
    +
    19741  1, // allocationCount
    +
    19742  pAllocation);
    +
    19743  *pAllocation = VK_NULL_HANDLE;
    +
    19744  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
    +
    19745  *pImage = VK_NULL_HANDLE;
    +
    19746  return res;
    +
    19747  }
    +
    19748  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
    +
    19749  *pImage = VK_NULL_HANDLE;
    +
    19750  return res;
    +
    19751  }
    +
    19752  return res;
    +
    19753 }
    +
    19754 
    +
    19755 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
    +
    19756  VmaAllocator allocator,
    +
    19757  VkImage image,
    +
    19758  VmaAllocation allocation)
    +
    19759 {
    +
    19760  VMA_ASSERT(allocator);
    +
    19761 
    +
    19762  if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
    +
    19763  {
    +
    19764  return;
    +
    19765  }
    +
    19766 
    +
    19767  VMA_DEBUG_LOG("vmaDestroyImage");
    +
    19768 
    +
    19769  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    +
    19770 
    +
    19771 #if VMA_RECORDING_ENABLED
    +
    19772  if(allocator->GetRecorder() != VMA_NULL)
    +
    19773  {
    +
    19774  allocator->GetRecorder()->RecordDestroyImage(
    +
    19775  allocator->GetCurrentFrameIndex(),
    +
    19776  allocation);
    +
    19777  }
    +
    19778 #endif
    +
    19779 
    +
    19780  if(image != VK_NULL_HANDLE)
    +
    19781  {
    +
    19782  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
    +
    19783  }
    +
    19784  if(allocation != VK_NULL_HANDLE)
    +
    19785  {
    +
    19786  allocator->FreeMemory(
    +
    19787  1, // allocationCount
    +
    19788  &allocation);
    +
    19789  }
    +
    19790 }
    +
    19791 
    +
    19792 #endif // #ifdef VMA_IMPLEMENTATION
    Definition: vk_mem_alloc.h:2900
    uint32_t memoryTypeBits
    Bitmask containing one bit set for every memory type acceptable for this allocation.
    Definition: vk_mem_alloc.h:2926
    VmaPool pool
    Pool that this allocation should be created in.
    Definition: vk_mem_alloc.h:2932
    @@ -16611,6 +16722,7 @@ $(function() {
    @ VMA_POOL_CREATE_ALGORITHM_MASK
    Definition: vk_mem_alloc.h:3058
    void vmaUnmapMemory(VmaAllocator allocator, VmaAllocation allocation)
    Unmaps memory represented by given allocation, mapped previously using vmaMapMemory().
    VkResult vmaDefragment(VmaAllocator allocator, const VmaAllocation *pAllocations, size_t allocationCount, VkBool32 *pAllocationsChanged, const VmaDefragmentationInfo *pDefragmentationInfo, VmaDefragmentationStats *pDefragmentationStats)
    Deprecated. Compacts memory by moving allocations.
    +
    VkResult vmaCreateBufferWithAlignment(VmaAllocator allocator, const VkBufferCreateInfo *pBufferCreateInfo, const VmaAllocationCreateInfo *pAllocationCreateInfo, VkDeviceSize minAlignment, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
    Creates a buffer with additional minimum alignment.
    struct VmaBudget VmaBudget
    Statistics of current memory usage and available budget, in bytes, for specific memory heap.
    void vmaBuildStatsString(VmaAllocator allocator, char **ppStatsString, VkBool32 detailedMap)
    Builds and returns statistics as string in JSON format.
    VmaMemoryUsage
    Definition: vk_mem_alloc.h:2721
    diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index ce73d6c..3ab71ed 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -3987,7 +3987,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation, VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); -/** \brief TODO +/** \brief Creates a buffer with additional minimum alignment. + +Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, +minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. +for interop with OpenGL. */ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( VmaAllocator VMA_NOT_NULL allocator,