Added new feature: corruption detection. Added debug macro VMA_DEBUG_DETECT_CORRUPTION, functions vmaCheckCorruption, vmaCheckPoolCorruption

This commit is contained in:
Adam Sawicki 2018-06-14 15:44:45 +02:00
parent 73b1665ea4
commit 212a4a6567
16 changed files with 733 additions and 123 deletions

View File

@ -50,6 +50,7 @@ Additional features:
- Debug annotations: Associate string with name or opaque pointer to your own data with every allocation.
- JSON dump: Obtain a string in JSON format with detailed map of internal state, including list of allocations and gaps between them.
- Convert this JSON dump into a picture to visualize your memory. See [tools/VmaDumpVis](tools/VmaDumpVis/README.md).
- Margins: Enable validation of a magic number before and after every allocation to detect out-of-bounds memory corruption.
# Prequisites

BIN
docs/gfx/Margins_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

BIN
docs/gfx/Margins_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

View File

@ -0,0 +1,100 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Vulkan Memory Allocator: Corruption detection</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Vulkan Memory Allocator
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div id="nav-path" class="navpath">
<ul>
<li class="navelem"><a class="el" href="index.html">Vulkan Memory Allocator</a></li> </ul>
</div>
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">Corruption detection </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>If you suspect a bug caused by memory being overwritten out of bounds of an allocation, you can use debug features of this library to verify this.</p>
<h1><a class="anchor" id="corruption_detection_margins"></a>
Margins</h1>
<p>By default, allocations are laid your in memory blocks next to each other if possible (considering required alignment, <code>bufferImageGranularity</code>, and <code>nonCoherentAtomSize</code>).</p>
<div class="image">
<img src="../gfx/Margins_1.png" alt="Allocations without margin"/>
</div>
<p>Define macro <code>VMA_DEBUG_MARGIN</code> to some non-zero value (e.g. 16) to enforce specified number of bytes as a margin before and after every allocation.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#define VMA_DEBUG_MARGIN 16</span></div><div class="line"><span class="preprocessor">#include &quot;vk_mem_alloc.h&quot;</span></div></div><!-- fragment --><div class="image">
<img src="../gfx/Margins_2.png" alt="Allocations with margin"/>
</div>
<p>If your bug goes away after enabling margins, it means it may be caused by memory being overwritten outside of allocation boundaries. It is not 100% certain though. Change in application behavior may also be caused by different order and distribution of allocations across memory blocks after margins are applied.</p>
<p>The margin is applied also before first and after last allocation in a block. It may happen only once between two adjacent allocations.</p>
<p>Margin is applied only to allocations made out of memory blocks and not to dedicated allocations, which have their own memory block of specific size. It is thus not applied to allocations made using <a class="el" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a3fc311d855c2ff53f1090ef5c722b38f" title="Set this flag if the allocation should have its own memory block. ">VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT</a> flag or those automatically decided to put into dedicated allocations, e.g. due to its large size or recommended by VK_KHR_dedicated_allocation extension.</p>
<p>Margins appear in <a class="el" href="statistics.html#statistics_json_dump">JSON dump</a> as part of free space.</p>
<p>Note that enabling margins increases memory usage and fragmentation.</p>
<h1><a class="anchor" id="corruption_detection_corruption_detection"></a>
Corruption detection</h1>
<p>You can additionally define macro <code>VMA_DEBUG_DETECT_CORRUPTION</code> to 1 to enable validation of contents of the margins.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#define VMA_DEBUG_MARGIN 16</span></div><div class="line"><span class="preprocessor">#define VMA_DEBUG_DETECT_CORRUPTION 1</span></div><div class="line"><span class="preprocessor">#include &quot;vk_mem_alloc.h&quot;</span></div></div><!-- fragment --><p>When this feature is enabled, number of bytes specified as <code>VMA_DEBUG_MARGIN</code> (it must be multiply of 4) before and after every allocation is filled with a magic number. This idea is also know as "canary". Memory is automatically mapped and unmapped if necessary.</p>
<p>This number is validated automatically when the allocation is destroyed. If it's not equal to the expected value, <code>VMA_ASSERT()</code> is executed. It clearly means that either CPU or GPU overwritten the memory outside of boundaries of the allocation, which indicates a serious bug.</p>
<p>You can also explicitly request checking margins of all allocations in all memory blocks that belong to specified memory types by using function <a class="el" href="vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98" title="Checks magic number in margins around all allocations in given memory types (in both default and cust...">vmaCheckCorruption()</a>, or in memory blocks that belong to specified custom pool, by using function <a class="el" href="vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89" title="Checks magic number in margins around all allocations in given memory pool in search for corruptions...">vmaCheckPoolCorruption()</a>.</p>
<p>Margin validation (corruption detection) works only for memory types that are <code>HOST_VISIBLE</code> and <code>HOST_COHERENT</code>. </p>
</div></div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
</body>
</html>

View File

@ -173,6 +173,12 @@ $(function() {
<li>vmaCalculateStats()
: <a class="el" href="vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3">vk_mem_alloc.h</a>
</li>
<li>vmaCheckCorruption()
: <a class="el" href="vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98">vk_mem_alloc.h</a>
</li>
<li>vmaCheckPoolCorruption()
: <a class="el" href="vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89">vk_mem_alloc.h</a>
</li>
<li>vmaCreateAllocator()
: <a class="el" href="vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb">vk_mem_alloc.h</a>
</li>

View File

@ -82,6 +82,12 @@ $(function() {
<li>vmaCalculateStats()
: <a class="el" href="vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3">vk_mem_alloc.h</a>
</li>
<li>vmaCheckCorruption()
: <a class="el" href="vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98">vk_mem_alloc.h</a>
</li>
<li>vmaCheckPoolCorruption()
: <a class="el" href="vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89">vk_mem_alloc.h</a>
</li>
<li>vmaCreateAllocator()
: <a class="el" href="vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb">vk_mem_alloc.h</a>
</li>

View File

@ -62,7 +62,7 @@ $(function() {
<div class="title">Vulkan Memory Allocator </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>Version 2.1.0-alpha.1</b> (2018-06-04)</p>
<div class="textblock"><p><b>Version 2.1.0-alpha.3</b> (2018-06-11)</p>
<p>Copyright (c) 2017-2018 Advanced Micro Devices, Inc. All rights reserved. <br />
License: MIT</p>
<p>Documentation of all members: <a class="el" href="vk__mem__alloc_8h.html">vk_mem_alloc.h</a></p>
@ -106,6 +106,11 @@ Table of contents</h1>
<li><a class="el" href="allocation_annotation.html#allocation_names">Allocation names</a></li>
</ul>
</li>
<li><a class="el" href="corruption_detection.html">Corruption detection</a><ul>
<li><a class="el" href="corruption_detection.html#corruption_detection_margins">Margins</a></li>
<li><a class="el" href="corruption_detection.html#corruption_detection_corruption_detection">Corruption detection</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="el" href="usage_patterns.html">Recommended usage patterns</a><ul>

View File

@ -2,5 +2,6 @@ var searchData=
[
['choosing_20memory_20type',['Choosing memory type',['../choosing_memory_type.html',1,'index']]],
['configuration',['Configuration',['../configuration.html',1,'index']]],
['corruption_20detection',['Corruption detection',['../corruption_detection.html',1,'index']]],
['custom_20memory_20pools',['Custom memory pools',['../custom_memory_pools.html',1,'index']]]
];

View File

@ -55,6 +55,8 @@ var searchData=
['vmabindimagememory',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]],
['vmabuildstatsstring',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]],
['vmacalculatestats',['vmaCalculateStats',['../vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]],
['vmacheckcorruption',['vmaCheckCorruption',['../vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98',1,'vk_mem_alloc.h']]],
['vmacheckpoolcorruption',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]],
['vmacreateallocator',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]],
['vmacreatebuffer',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]],
['vmacreateimage',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]],

View File

@ -7,6 +7,8 @@ var searchData=
['vmabindimagememory',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]],
['vmabuildstatsstring',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]],
['vmacalculatestats',['vmaCalculateStats',['../vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]],
['vmacheckcorruption',['vmaCheckCorruption',['../vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98',1,'vk_mem_alloc.h']]],
['vmacheckpoolcorruption',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]],
['vmacreateallocator',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]],
['vmacreatebuffer',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]],
['vmacreateimage',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]],

View File

@ -2,5 +2,6 @@ var searchData=
[
['choosing_20memory_20type',['Choosing memory type',['../choosing_memory_type.html',1,'index']]],
['configuration',['Configuration',['../configuration.html',1,'index']]],
['corruption_20detection',['Corruption detection',['../corruption_detection.html',1,'index']]],
['custom_20memory_20pools',['Custom memory pools',['../custom_memory_pools.html',1,'index']]]
];

View File

@ -257,6 +257,9 @@ Functions</h2></td></tr>
<tr class="memitem:a736bd6cbda886f36c891727e73bd4024"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024">vmaMakePoolAllocationsLost</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_pool.html">VmaPool</a> pool, size_t *pLostAllocationCount)</td></tr>
<tr class="memdesc:a736bd6cbda886f36c891727e73bd4024"><td class="mdescLeft">&#160;</td><td class="mdescRight">Marks all allocations in given pool as lost if they are not used in current frame or <a class="el" href="struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa" title="Maximum number of additional frames that are in use at the same time as current frame. ">VmaPoolCreateInfo::frameInUseCount</a> back from now. <a href="#a736bd6cbda886f36c891727e73bd4024">More...</a><br /></td></tr>
<tr class="separator:a736bd6cbda886f36c891727e73bd4024"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ad535935619c7a549bf837e1bb0068f89"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89">vmaCheckPoolCorruption</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_pool.html">VmaPool</a> pool)</td></tr>
<tr class="memdesc:ad535935619c7a549bf837e1bb0068f89"><td class="mdescLeft">&#160;</td><td class="mdescRight">Checks magic number in margins around all allocations in given memory pool in search for corruptions. <a href="#ad535935619c7a549bf837e1bb0068f89">More...</a><br /></td></tr>
<tr class="separator:ad535935619c7a549bf837e1bb0068f89"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:abf28077dbf82d0908b8acbe8ee8dd9b8"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8">vmaAllocateMemory</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, const VkMemoryRequirements *pVkMemoryRequirements, const <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> *pCreateInfo, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocation, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
<tr class="memdesc:abf28077dbf82d0908b8acbe8ee8dd9b8"><td class="mdescLeft">&#160;</td><td class="mdescRight">General purpose memory allocation. <a href="#abf28077dbf82d0908b8acbe8ee8dd9b8">More...</a><br /></td></tr>
<tr class="separator:abf28077dbf82d0908b8acbe8ee8dd9b8"><td class="memSeparator" colspan="2">&#160;</td></tr>
@ -292,6 +295,9 @@ Functions</h2></td></tr>
<tr class="memitem:a0d0eb0c1102268fa9a476d12ecbe4006"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a0d0eb0c1102268fa9a476d12ecbe4006">vmaInvalidateAllocation</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation, VkDeviceSize offset, VkDeviceSize size)</td></tr>
<tr class="memdesc:a0d0eb0c1102268fa9a476d12ecbe4006"><td class="mdescLeft">&#160;</td><td class="mdescRight">Invalidates memory of given allocation. <a href="#a0d0eb0c1102268fa9a476d12ecbe4006">More...</a><br /></td></tr>
<tr class="separator:a0d0eb0c1102268fa9a476d12ecbe4006"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a49329a7f030dafcf82f7b73334c22e98"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98">vmaCheckCorruption</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, uint32_t memoryTypeBits)</td></tr>
<tr class="memdesc:a49329a7f030dafcf82f7b73334c22e98"><td class="mdescLeft">&#160;</td><td class="mdescRight">Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. <a href="#a49329a7f030dafcf82f7b73334c22e98">More...</a><br /></td></tr>
<tr class="separator:a49329a7f030dafcf82f7b73334c22e98"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a6aced90fcc7b39882b6654a740a0b9bb"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a6aced90fcc7b39882b6654a740a0b9bb">vmaDefragment</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocations, size_t allocationCount, VkBool32 *pAllocationsChanged, const <a class="el" href="struct_vma_defragmentation_info.html">VmaDefragmentationInfo</a> *pDefragmentationInfo, <a class="el" href="struct_vma_defragmentation_stats.html">VmaDefragmentationStats</a> *pDefragmentationStats)</td></tr>
<tr class="memdesc:a6aced90fcc7b39882b6654a740a0b9bb"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compacts memory by moving allocations. <a href="#a6aced90fcc7b39882b6654a740a0b9bb">More...</a><br /></td></tr>
<tr class="separator:a6aced90fcc7b39882b6654a740a0b9bb"><td class="memSeparator" colspan="2">&#160;</td></tr>
@ -1105,6 +1111,88 @@ Functions</h2></td></tr>
<p>Retrieves statistics from current state of the Allocator. </p>
</div>
</div>
<a id="a49329a7f030dafcf82f7b73334c22e98"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a49329a7f030dafcf82f7b73334c22e98">&#9670;&nbsp;</a></span>vmaCheckCorruption()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">VkResult vmaCheckCorruption </td>
<td>(</td>
<td class="paramtype"><a class="el" href="struct_vma_allocator.html">VmaAllocator</a>&#160;</td>
<td class="paramname"><em>allocator</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">uint32_t&#160;</td>
<td class="paramname"><em>memoryTypeBits</em>&#160;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">memoryTypeBits</td><td>Bit mask, where each bit set means that a memory type with that index should be checked.</td></tr>
</table>
</dd>
</dl>
<p>Corruption detection is enabled only when <code>VMA_DEBUG_DETECT_CORRUPTION</code> macro is defined to nonzero, <code>VMA_DEBUG_MARGIN</code> is defined to nonzero and only for memory types that are <code>HOST_VISIBLE</code> and <code>HOST_COHERENT</code>. For more information, see <a class="el" href="corruption_detection.html">Corruption detection</a>.</p>
<p>Possible return values:</p>
<ul>
<li><code>VK_ERROR_FEATURE_NOT_PRESENT</code> - corruption detection is not enabled for any of specified memory types.</li>
<li><code>VK_SUCCESS</code> - corruption detection has been performed and succeeded.</li>
<li><code>VK_ERROR_VALIDATION_FAILED_EXT</code> - corruption detection has been performed and found memory corruptions around one of the allocations. <code>VMA_ASSERT</code> is also fired in that case.</li>
<li>Other value: Error returned by Vulkan, e.g. memory mapping failure. </li>
</ul>
</div>
</div>
<a id="ad535935619c7a549bf837e1bb0068f89"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ad535935619c7a549bf837e1bb0068f89">&#9670;&nbsp;</a></span>vmaCheckPoolCorruption()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">VkResult vmaCheckPoolCorruption </td>
<td>(</td>
<td class="paramtype"><a class="el" href="struct_vma_allocator.html">VmaAllocator</a>&#160;</td>
<td class="paramname"><em>allocator</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype"><a class="el" href="struct_vma_pool.html">VmaPool</a>&#160;</td>
<td class="paramname"><em>pool</em>&#160;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Checks magic number in margins around all allocations in given memory pool in search for corruptions. </p>
<p>Corruption detection is enabled only when <code>VMA_DEBUG_DETECT_CORRUPTION</code> macro is defined to nonzero, <code>VMA_DEBUG_MARGIN</code> is defined to nonzero and the pool is created in memory type that is <code>HOST_VISIBLE</code> and <code>HOST_COHERENT</code>. For more information, see <a class="el" href="corruption_detection.html">Corruption detection</a>.</p>
<p>Possible return values:</p>
<ul>
<li><code>VK_ERROR_FEATURE_NOT_PRESENT</code> - corruption detection is not enabled for specified pool.</li>
<li><code>VK_SUCCESS</code> - corruption detection has been performed and succeeded.</li>
<li><code>VK_ERROR_VALIDATION_FAILED_EXT</code> - corruption detection has been performed and found memory corruptions around one of the allocations. <code>VMA_ASSERT</code> is also fired in that case.</li>
<li>Other value: Error returned by Vulkan, e.g. memory mapping failure. </li>
</ul>
</div>
</div>
<a id="a200692051ddb34240248234f5f4c17bb"></a>

File diff suppressed because one or more lines are too long

View File

@ -1322,6 +1322,7 @@ void TestHeapSizeLimit()
vmaDestroyAllocator(hAllocator);
}
#if VMA_DEBUG_MARGIN
static void TestDebugMargin()
{
if(VMA_DEBUG_MARGIN == 0)
@ -1330,10 +1331,10 @@ static void TestDebugMargin()
}
VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
// Create few buffers of different size.
const size_t BUF_COUNT = 10;
@ -1342,11 +1343,21 @@ static void TestDebugMargin()
for(size_t i = 0; i < 10; ++i)
{
bufInfo.size = (VkDeviceSize)(i + 1) * 64;
// Last one will be mapped.
allocCreateInfo.flags = (i == BUF_COUNT - 1) ? VMA_ALLOCATION_CREATE_MAPPED_BIT : 0;
VkResult res = vmaCreateBuffer(g_hAllocator, &bufInfo, &allocCreateInfo, &buffers[i].Buffer, &buffers[i].Allocation, &allocInfo[i]);
assert(res == VK_SUCCESS);
// Margin is preserved also at the beginning of a block.
assert(allocInfo[i].offset >= VMA_DEBUG_MARGIN);
if(i == BUF_COUNT - 1)
{
// Fill with data.
assert(allocInfo[i].pMappedData != nullptr);
// Uncomment this "+ 1" to overwrite past end of allocation and check corruption detection.
memset(allocInfo[i].pMappedData, 0xFF, bufInfo.size /* + 1 */);
}
}
// Check if their offsets preserve margin between them.
@ -1366,12 +1377,16 @@ static void TestDebugMargin()
}
}
VkResult res = vmaCheckCorruption(g_hAllocator, UINT32_MAX);
assert(res == VK_SUCCESS);
// Destroy all buffers.
for(size_t i = BUF_COUNT; i--; )
{
vmaDestroyBuffer(g_hAllocator, buffers[i].Buffer, buffers[i].Allocation);
}
}
#endif
static void TestPool_SameSize()
{
@ -3004,18 +3019,17 @@ void Test()
{
wprintf(L"TESTING:\n");
// TEMP tests
// # Simple tests
TestBasics();
if(VMA_DEBUG_MARGIN)
{
TestDebugMargin();
}
else
{
TestPool_SameSize();
TestHeapSizeLimit();
}
#if VMA_DEBUG_MARGIN
TestDebugMargin();
#else
TestPool_SameSize();
TestHeapSizeLimit();
#endif
TestMapping();
TestMappingMultithreaded();
TestDefragmentationSimple();

View File

@ -18,10 +18,13 @@ include all public interface declarations. Example:
//#define VMA_USE_STL_CONTAINERS 1
//#define VMA_HEAVY_ASSERT(expr)
//#define VMA_HEAVY_ASSERT(expr) assert(expr)
//#define VMA_DEDICATED_ALLOCATION 0
//#define VMA_DEBUG_MARGIN 16
//#define VMA_DEBUG_DETECT_CORRUPTION 1
#pragma warning(push, 4)
#pragma warning(disable: 4127) // conditional expression is constant
#pragma warning(disable: 4100) // unreferenced formal parameter

View File

@ -29,7 +29,7 @@ extern "C" {
/** \mainpage Vulkan Memory Allocator
<b>Version 2.1.0-alpha.2</b> (2018-06-08)
<b>Version 2.1.0-alpha.3</b> (2018-06-14)
Copyright (c) 2017-2018 Advanced Micro Devices, Inc. All rights reserved. \n
License: MIT
@ -63,6 +63,9 @@ Documentation of all members: vk_mem_alloc.h
- \subpage allocation_annotation
- [Allocation user data](@ref allocation_user_data)
- [Allocation names](@ref allocation_names)
- \subpage corruption_detection
- [Margins](@ref corruption_detection_margins)
- [Corruption detection](@ref corruption_detection_corruption_detection)
- \subpage usage_patterns
- [Simple patterns](@ref usage_patterns_simple)
- [Advanced patterns](@ref usage_patterns_advanced)
@ -810,6 +813,76 @@ printf("Image name: %s\n", imageName);
That string is also printed in JSON report created by vmaBuildStatsString().
\page corruption_detection Corruption detection
If you suspect a bug caused by memory being overwritten out of bounds of an allocation,
you can use debug features of this library to verify this.
\section corruption_detection_margins Margins
By default, allocations are laid your in memory blocks next to each other if possible
(considering required alignment, `bufferImageGranularity`, and `nonCoherentAtomSize`).
![Allocations without margin](../gfx/Margins_1.png)
Define macro `VMA_DEBUG_MARGIN` to some non-zero value (e.g. 16) to enforce specified
number of bytes as a margin before and after every allocation.
\code
#define VMA_DEBUG_MARGIN 16
#include "vk_mem_alloc.h"
\endcode
![Allocations with margin](../gfx/Margins_2.png)
If your bug goes away after enabling margins, it means it may be caused by memory
being overwritten outside of allocation boundaries. It is not 100% certain though.
Change in application behavior may also be caused by different order and distribution
of allocations across memory blocks after margins are applied.
The margin is applied also before first and after last allocation in a block.
It may happen only once between two adjacent allocations.
Margin is applied only to allocations made out of memory blocks and not to dedicated
allocations, which have their own memory block of specific size.
It is thus not applied to allocations made using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT flag
or those automatically decided to put into dedicated allocations, e.g. due to its
large size or recommended by VK_KHR_dedicated_allocation extension.
Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space.
Note that enabling margins increases memory usage and fragmentation.
\section corruption_detection_corruption_detection Corruption detection
You can additionally define macro `VMA_DEBUG_DETECT_CORRUPTION` to 1 to enable validation
of contents of the margins.
\code
#define VMA_DEBUG_MARGIN 16
#define VMA_DEBUG_DETECT_CORRUPTION 1
#include "vk_mem_alloc.h"
\endcode
When this feature is enabled, number of bytes specified as `VMA_DEBUG_MARGIN`
(it must be multiply of 4) before and after every allocation is filled with a magic number.
This idea is also know as "canary".
Memory is automatically mapped and unmapped if necessary.
This number is validated automatically when the allocation is destroyed.
If it's not equal to the expected value, `VMA_ASSERT()` is executed.
It clearly means that either CPU or GPU overwritten the memory outside of boundaries of the allocation,
which indicates a serious bug.
You can also explicitly request checking margins of all allocations in all memory blocks
that belong to specified memory types by using function vmaCheckCorruption(),
or in memory blocks that belong to specified custom pool, by using function
vmaCheckPoolCorruption().
Margin validation (corruption detection) works only for memory types that are
`HOST_VISIBLE` and `HOST_COHERENT`.
\page usage_patterns Recommended usage patterns
See also slides from talk:
@ -1722,6 +1795,22 @@ void vmaMakePoolAllocationsLost(
VmaPool pool,
size_t* pLostAllocationCount);
/** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions.
Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero,
`VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is
`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref corruption_detection).
Possible return values:
- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool.
- `VK_SUCCESS` - corruption detection has been performed and succeeded.
- `VK_ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations.
`VMA_ASSERT` is also fired in that case.
- Other value: Error returned by Vulkan, e.g. memory mapping failure.
*/
VkResult vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool);
/** \struct VmaAllocation
\brief Represents single memory allocation.
@ -1980,6 +2069,24 @@ Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range
*/
void vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions.
@param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked.
Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero,
`VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are
`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref corruption_detection).
Possible return values:
- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types.
- `VK_SUCCESS` - corruption detection has been performed and succeeded.
- `VK_ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations.
`VMA_ASSERT` is also fired in that case.
- Other value: Error returned by Vulkan, e.g. memory mapping failure.
*/
VkResult vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits);
/** \brief Optional configuration parameters to be passed to function vmaDefragment(). */
typedef struct VmaDefragmentationInfo {
/** \brief Maximum total numbers of bytes that can be copied while moving allocations to different places.
@ -2453,6 +2560,15 @@ If providing your own implementation, you need to implement a subset of std::ato
#define VMA_DEBUG_MARGIN (0)
#endif
#ifndef VMA_DEBUG_DETECT_CORRUPTION
/**
Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to
enable writing magic value to the margin before and after every allocation and
validating it, so that memory corruptions (out-of-bounds writes) are detected.
*/
#define VMA_DEBUG_DETECT_CORRUPTION (0)
#endif
#ifndef VMA_DEBUG_GLOBAL_MUTEX
/**
Set this to 1 for debugging purposes only, to enable single mutex protecting all
@ -2488,6 +2604,9 @@ If providing your own implementation, you need to implement a subset of std::ato
static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
// Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F.
static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666;
/*******************************************************************************
END OF CONFIGURATION
*/
@ -2641,6 +2760,30 @@ static inline bool VmaIsBufferImageGranularityConflict(
}
}
static void VmaWriteMagicValue(void* pData, VkDeviceSize offset)
{
uint32_t* pDst = (uint32_t*)((char*)pData + offset);
const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
for(size_t i = 0; i < numberCount; ++i, ++pDst)
{
*pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE;
}
}
static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset)
{
const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset);
const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
for(size_t i = 0; i < numberCount; ++i, ++pSrc)
{
if(*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE)
{
return false;
}
}
return true;
}
// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
struct VmaMutexLock
{
@ -4101,6 +4244,8 @@ public:
uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
VkResult CheckCorruption(const void* pBlockData);
// Makes actual allocation based on request. Request must already be checked and valid.
void Alloc(
const VmaAllocationRequest& request,
@ -4189,10 +4334,15 @@ public:
// Validates all data structures inside this object. If not valid, returns false.
bool Validate() const;
VkResult CheckCorruption(VmaAllocator hAllocator);
// ppData can be null.
VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData);
void Unmap(VmaAllocator hAllocator, uint32_t count);
VkResult WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
VkResult ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
VkResult BindBufferMemory(
const VmaAllocator hAllocator,
const VmaAllocation hAllocation,
@ -4255,6 +4405,7 @@ public:
void GetPoolStats(VmaPoolStats* pStats);
bool IsEmpty() const { return m_Blocks.empty(); }
bool IsCorruptionDetectionEnabled() const;
VkResult Allocate(
VmaPool hCurrentPool,
@ -4278,6 +4429,7 @@ public:
void MakePoolAllocationsLost(
uint32_t currentFrameIndex,
size_t* pLostAllocationCount);
VkResult CheckCorruption();
VmaDefragmentator* EnsureDefragmentator(
VmaAllocator hAllocator,
@ -4599,6 +4751,8 @@ public:
void MakePoolAllocationsLost(
VmaPool hPool,
size_t* pLostAllocationCount);
VkResult CheckPoolCorruption(VmaPool hPool);
VkResult CheckCorruption(uint32_t memoryTypeBits);
void CreateLostAllocation(VmaAllocation* pAllocation);
@ -5888,6 +6042,30 @@ uint32_t VmaBlockMetadata::MakeAllocationsLost(uint32_t currentFrameIndex, uint3
return lostAllocationCount;
}
VkResult VmaBlockMetadata::CheckCorruption(const void* pBlockData)
{
for(VmaSuballocationList::iterator it = m_Suballocations.begin();
it != m_Suballocations.end();
++it)
{
if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
{
if(!VmaValidateMagicValue(pBlockData, it->offset - VMA_DEBUG_MARGIN))
{
VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
return VK_ERROR_VALIDATION_FAILED_EXT;
}
if(!VmaValidateMagicValue(pBlockData, it->offset + it->size))
{
VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
return VK_ERROR_VALIDATION_FAILED_EXT;
}
}
}
return VK_SUCCESS;
}
void VmaBlockMetadata::Alloc(
const VmaAllocationRequest& request,
VmaSuballocationType type,
@ -6462,6 +6640,22 @@ bool VmaDeviceMemoryBlock::Validate() const
return m_Metadata.Validate();
}
VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator)
{
void* pData = nullptr;
VkResult res = Map(hAllocator, 1, &pData);
if(res != VK_SUCCESS)
{
return res;
}
res = m_Metadata.CheckCorruption(pData);
Unmap(hAllocator, 1);
return res;
}
VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData)
{
if(count == 0)
@ -6524,6 +6718,52 @@ void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count)
}
}
VkResult VmaDeviceMemoryBlock::WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
{
VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
void* pData;
VkResult res = Map(hAllocator, 1, &pData);
if(res != VK_SUCCESS)
{
return res;
}
VmaWriteMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN);
VmaWriteMagicValue(pData, allocOffset + allocSize);
Unmap(hAllocator, 1);
return VK_SUCCESS;
}
VkResult VmaDeviceMemoryBlock::ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
{
VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
void* pData;
VkResult res = Map(hAllocator, 1, &pData);
if(res != VK_SUCCESS)
{
return res;
}
if(!VmaValidateMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN))
{
VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE FREED ALLOCATION!");
}
else if(!VmaValidateMagicValue(pData, allocOffset + allocSize))
{
VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!");
}
Unmap(hAllocator, 1);
return VK_SUCCESS;
}
VkResult VmaDeviceMemoryBlock::BindBufferMemory(
const VmaAllocator hAllocator,
const VmaAllocation hAllocation,
@ -6676,6 +6916,14 @@ void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
}
}
bool VmaBlockVector::IsCorruptionDetectionEnabled() const
{
const uint32_t requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
return (VMA_DEBUG_DETECT_CORRUPTION != 0) &&
(VMA_DEBUG_MARGIN > 0) &&
(m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags;
}
static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
VkResult VmaBlockVector::Allocate(
@ -6747,6 +6995,11 @@ VkResult VmaBlockVector::Allocate(
VMA_HEAVY_ASSERT(pCurrBlock->Validate());
VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)blockIndex);
(*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
if(IsCorruptionDetectionEnabled())
{
VkResult res = pCurrBlock->WriteMagicValueAroundAllocation(m_hAllocator, currRequest.offset, size);
VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
}
return VK_SUCCESS;
}
}
@ -6845,6 +7098,11 @@ VkResult VmaBlockVector::Allocate(
VMA_HEAVY_ASSERT(pBlock->Validate());
VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize);
(*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
if(IsCorruptionDetectionEnabled())
{
res = pBlock->WriteMagicValueAroundAllocation(m_hAllocator, allocRequest.offset, size);
VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
}
return VK_SUCCESS;
}
else
@ -6936,6 +7194,11 @@ VkResult VmaBlockVector::Allocate(
VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)blockIndex);
(*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
if(IsCorruptionDetectionEnabled())
{
VkResult res = pBestRequestBlock->WriteMagicValueAroundAllocation(m_hAllocator, bestRequest.offset, size);
VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
}
return VK_SUCCESS;
}
// else: Some allocations must have been touched while we are here. Next try.
@ -6969,6 +7232,12 @@ void VmaBlockVector::Free(
VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
if(IsCorruptionDetectionEnabled())
{
VkResult res = pBlock->ValidateMagicValueAroundAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize());
VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value.");
}
if(hAllocation->IsPersistentMap())
{
pBlock->Unmap(m_hAllocator, 1);
@ -7251,6 +7520,27 @@ void VmaBlockVector::MakePoolAllocationsLost(
}
}
VkResult VmaBlockVector::CheckCorruption()
{
if(!IsCorruptionDetectionEnabled())
{
return VK_ERROR_FEATURE_NOT_PRESENT;
}
VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
{
VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
VMA_ASSERT(pBlock);
VkResult res = pBlock->CheckCorruption(m_hAllocator);
if(res != VK_SUCCESS)
{
return res;
}
}
return VK_SUCCESS;
}
void VmaBlockVector::AddStats(VmaStats* pStats)
{
const uint32_t memTypeIndex = m_MemoryTypeIndex;
@ -7425,6 +7715,12 @@ VkResult VmaDefragmentator::DefragmentRound(
reinterpret_cast<char*>(pSrcMappedData) + srcOffset,
static_cast<size_t>(size));
if(VMA_DEBUG_MARGIN > 0)
{
VmaWriteMagicValue(pDstMappedData, dstAllocRequest.offset - VMA_DEBUG_MARGIN);
VmaWriteMagicValue(pDstMappedData, dstAllocRequest.offset + size);
}
pDstBlockInfo->m_pBlock->m_Metadata.Alloc(dstAllocRequest, suballocType, size, allocInfo.m_hAllocation);
pSrcBlockInfo->m_pBlock->m_Metadata.FreeAtOffset(srcOffset);
@ -7568,6 +7864,12 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
m_Pools(VmaStlAllocator<VmaPool>(GetAllocationCallbacks())),
m_NextPoolId(0)
{
if(VMA_DEBUG_DETECT_CORRUPTION)
{
// Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it.
VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0);
}
VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device);
#if !(VMA_DEDICATED_ALLOCATION)
@ -8518,6 +8820,61 @@ void VmaAllocator_T::MakePoolAllocationsLost(
pLostAllocationCount);
}
VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool)
{
return hPool->m_BlockVector.CheckCorruption();
}
VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits)
{
VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT;
// Process default pools.
for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
{
if(((1u << memTypeIndex) & memoryTypeBits) != 0)
{
VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
VMA_ASSERT(pBlockVector);
VkResult localRes = pBlockVector->CheckCorruption();
switch(localRes)
{
case VK_ERROR_FEATURE_NOT_PRESENT:
break;
case VK_SUCCESS:
finalRes = VK_SUCCESS;
break;
default:
return localRes;
}
}
}
// Process custom pools.
{
VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex)
{
if(((1u << m_Pools[poolIndex]->GetBlockVector().GetMemoryTypeIndex()) & memoryTypeBits) != 0)
{
VkResult localRes = m_Pools[poolIndex]->GetBlockVector().CheckCorruption();
switch(localRes)
{
case VK_ERROR_FEATURE_NOT_PRESENT:
break;
case VK_SUCCESS:
finalRes = VK_SUCCESS;
break;
default:
return localRes;
}
}
}
}
return finalRes;
}
void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
{
*pAllocation = vma_new(this, VmaAllocation_T)(VMA_FRAME_INDEX_LOST, false);
@ -9294,6 +9651,17 @@ void vmaMakePoolAllocationsLost(
allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
}
VkResult vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool)
{
VMA_ASSERT(allocator && pool);
VMA_DEBUG_GLOBAL_MUTEX_LOCK
VMA_DEBUG_LOG("vmaCheckPoolCorruption");
return allocator->CheckPoolCorruption(pool);
}
VkResult vmaAllocateMemory(
VmaAllocator allocator,
const VkMemoryRequirements* pVkMemoryRequirements,
@ -9495,6 +9863,17 @@ void vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, V
allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
}
VkResult vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits)
{
VMA_ASSERT(allocator);
VMA_DEBUG_LOG("vmaCheckCorruption");
VMA_DEBUG_GLOBAL_MUTEX_LOCK
return allocator->CheckCorruption(memoryTypeBits);
}
VkResult vmaDefragment(
VmaAllocator allocator,
VmaAllocation* pAllocations,