Skip to content

Commit d6ff05e

Browse files
Updated documentation regarding thread safety of defragmentation
1 parent 6a61103 commit d6ff05e

2 files changed

Lines changed: 14 additions & 2 deletions

File tree

docs/html/defragmentation.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@
182182
<p >You can defragment a specific custom pool by calling <a class="el" href="class_d3_d12_m_a_1_1_pool.html#adc87bb49c192de8f5a9ca0484c499575" title="Begins defragmentation process of the current pool.">D3D12MA::Pool::BeginDefragmentation</a> or all the default pools by calling <a class="el" href="class_d3_d12_m_a_1_1_allocator.html#a08e1468f1dbb63ce3bf6680e592b2143" title="Begins defragmentation process of the default pools.">D3D12MA::Allocator::BeginDefragmentation</a> (like in the example above).</p>
183183
<p >Defragmentation is always performed in each pool separately. Allocations are never moved between different heap types. The size of the destination memory reserved for a moved allocation is the same as the original one. Alignment of an allocation as it was determined using <code>GetResourceAllocationInfo()</code> is also respected after defragmentation. Buffers/textures should be recreated with the same <code>D3D12_RESOURCE_DESC</code> parameters as the original ones.</p>
184184
<p >You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved in each pass, e.g. to call it in sync with render frames and not to experience too big hitches. See members: <a class="el" href="struct_d3_d12_m_a_1_1_d_e_f_r_a_g_m_e_n_t_a_t_i_o_n___d_e_s_c.html#ad8d224e0687a35898970d0a5688c6343" title="Maximum numbers of bytes that can be copied during single pass, while moving allocations to different...">D3D12MA::DEFRAGMENTATION_DESC::MaxBytesPerPass</a>, <a class="el" href="struct_d3_d12_m_a_1_1_d_e_f_r_a_g_m_e_n_t_a_t_i_o_n___d_e_s_c.html#a83bfb404f387863eafdd6703483aed89" title="Maximum number of allocations that can be moved during single pass to a different place.">D3D12MA::DEFRAGMENTATION_DESC::MaxAllocationsPerPass</a>.</p>
185-
<p >It is also safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and D3D12MA usage, possibly from multiple threads, with the exception that allocations returned in <a class="el" href="struct_d3_d12_m_a_1_1_d_e_f_r_a_g_m_e_n_t_a_t_i_o_n___p_a_s_s___m_o_v_e___i_n_f_o.html#a719fbdaae54251759605c41baeb24dc4" title="Array of moves to be performed by the user in the current defragmentation pass.">D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO::pMoves</a> shouldn't be released until the defragmentation pass is ended.</p>
185+
<p ><b>Thread safety:</b> It is safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and D3D12MA usage, possibly from multiple threads, with the exception that allocations returned in <a class="el" href="struct_d3_d12_m_a_1_1_d_e_f_r_a_g_m_e_n_t_a_t_i_o_n___p_a_s_s___m_o_v_e___i_n_f_o.html#a719fbdaae54251759605c41baeb24dc4" title="Array of moves to be performed by the user in the current defragmentation pass.">D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO::pMoves</a> shouldn't be released until the defragmentation pass is ended. During the call to <a class="el" href="class_d3_d12_m_a_1_1_defragmentation_context.html#a1606c015d02edc094bb246986159d592" title="Starts single defragmentation pass.">D3D12MA::DefragmentationContext::BeginPass()</a>, any operations on the memory pool affected by the defragmentation are blocked by a mutex.</p>
186+
<p >What it means in practice is that you shouldn't free any allocations from the defragmented pool since the moment a call to <code>BeginPass</code> begins. Otherwise, a thread performing the <code>allocation-&gt;Release()</code> would block for the time <code>BeginPass</code> executes and then free the allocation when it finishes, while the allocation could have ended up on the list of allocations to move. A solution to freeing allocations during defragmentation is to find such allocation on the list <code>pass.pMoves[i]</code> and set its operation to <a class="el" href="namespace_d3_d12_m_a.html#a82bb787a69699a877b4166789a30e602aa2143507d723de458c2ed94e143ac242" title="Set this value if you decide to abandon the allocation and you destroyed the resource....">D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY</a> instead of calling <code>allocation-&gt;Release()</code>, or simply deferring the release to the time after defragmentation finished.</p>
186187
<p ><b>Mapping</b> is out of scope of this library and so it is not preserved after an allocation is moved during defragmentation. You need to map the new resource yourself if needed.</p>
187188
<dl class="section note"><dt>Note</dt><dd>Defragmentation is not supported in custom pools created with <a class="el" href="namespace_d3_d12_m_a.html#a919d8545365d6b7209a964f2b99936d1aa37a0103f511954ea42a1d0bba286b6a" title="Enables alternative, linear allocation algorithm in this pool.">D3D12MA::POOL_FLAG_ALGORITHM_LINEAR</a>. </dd></dl>
188189
</div></div><!-- contents -->

include/D3D12MemAlloc.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1965,9 +1965,20 @@ You can perform the defragmentation incrementally to limit the number of allocat
19651965
in each pass, e.g. to call it in sync with render frames and not to experience too big hitches.
19661966
See members: D3D12MA::DEFRAGMENTATION_DESC::MaxBytesPerPass, D3D12MA::DEFRAGMENTATION_DESC::MaxAllocationsPerPass.
19671967
1968-
It is also safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and %D3D12MA
1968+
<b>Thread safety:</b>
1969+
It is safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and %D3D12MA
19691970
usage, possibly from multiple threads, with the exception that allocations
19701971
returned in D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO::pMoves shouldn't be released until the defragmentation pass is ended.
1972+
During the call to D3D12MA::DefragmentationContext::BeginPass(), any operations on the memory pool
1973+
affected by the defragmentation are blocked by a mutex.
1974+
1975+
What it means in practice is that you shouldn't free any allocations from the defragmented pool
1976+
since the moment a call to `BeginPass` begins. Otherwise, a thread performing the `allocation->Release()`
1977+
would block for the time `BeginPass` executes and then free the allocation when it finishes, while the allocation
1978+
could have ended up on the list of allocations to move.
1979+
A solution to freeing allocations during defragmentation is to find such allocation on the list
1980+
`pass.pMoves[i]` and set its operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY instead of
1981+
calling `allocation->Release()`, or simply deferring the release to the time after defragmentation finished.
19711982
19721983
<b>Mapping</b> is out of scope of this library and so it is not preserved after an allocation is moved during defragmentation.
19731984
You need to map the new resource yourself if needed.

0 commit comments

Comments
 (0)