D3D12MemoryAllocator
D3D12MemoryAllocator copied to clipboard
Is D3D12MA::Allocator::BeginDefragmentation() Work Correctly ?
Our in-house engine use D3D12MA as D3D12 backend's native memory allocator, and I found that placed memory fragments get more and more with game running. By read document, I found there is a interface called D3D12MA::Allocator::BeginDefragmentation
can help heap allocation defragment. But after transplanted code from official sample, I just got some overlapped placed resources in heaps, like this in NSight Graphics:
Our resources' copy, create, access and destroy can happened on multi-thread, and resources' lifecycle is managed by intelligent pointers, but I have checked if a defragment action scheduled, any of resources' operation will blocked by mutex, and old resources' ref count will be set to 0 after defragment action.
So I got puzzled, I can not find any meaningful code on web except official sample, is D3D12MA really support defragment ? Could you have some more complex sample which can shared with us ?
Hi!
Could you please provide steps that you are using for defragmentation? Generally speaking, after starting defragmentation all resources that are selected to move (listed in DEFRAGMENTATION_PASS_MOVE_INFO
passed into DefragmentationContext::BeginPass()
) are needed to be recreated in new places so older resources will be released and their ID3D12Resource
pointers will be invalid. These steps are also described in here. Since you are using multiple threads for that, you must ensure that after committing single defragmentation pass (calling DefragmentationContext::EndPass()
) all your own routines are using correct pointers to new resources. This will require some synchronization to ensure no hazards. You can also look at the tests methods for more examples on how to use defragmentation.
Sorry about I forget to update this issue. I have checked if use many locks and some hard code to limit all the thing executed in a strict order, the library work correctly. Now what confuse me is the document specific that user need flush all graphics commands to make sure old allocation's data copy to the new one before DefragmentationContext::EndPass()
, which is OK when wait fence every frame, because after flush we can update resource pointers and recreate resource views easily, when record graphics commands next time, everything is ready, no outdate resources are used. Unfortunately our in-house engine use inflight commit model, which means there are many command list executing inflight. Inflight model can brings some annoying problems, e.g. DefragmentationContext::EndPass()
will release allocation after swap defragment src and dest, but at most time the resource is still used in inflight command list, so we can only defer the release process, which made lifecycle management bad.
For some reason, I can not show you code. So for inflight model, any suggestions ? Your reply is helpful for me, thanks!
Hi, currently there is no mechanism that would allow for synchronization of such case where there might be several overlapping command lists that use resources used for defragmentation. Solution I can think of would be to set selected resources that are in flight to ignore them in current defragmentation pass or postponing executing such pass by few frames, which will result in delay in calling EndPass(). Some other mechanism that I can think of but would require changes inside the library would be to add possibility to postpone deletion of resources by few frames while switching to newly created ones for further frames. Would that sound like a desired solution?
Sounds feasible, I will try those mechanisms later, thanks you.