Closed thatcosmonaut closed 3 years ago
After some extensive testing, I have made a few revisions to the defrag strategy:
1) We now walk the descriptor set cache and framebuffer cache when an image view is destroyed to invalidate resources that reference that image. This was causing device loss errors when Vulkan gave us a reused image view handle.
2) Buffer uploads wait on the defrag fence to avoid a data race if the GPU happens to be copying a buffer at the same time as the upload occurs.
3) Defrag is now incremental - defrag triggers 5 frames after a resource free and continues one allocation at a time every 5 frames until fragmentation is eliminated. This prevents defrag from constantly churning while resources are being loaded/unloaded and smooths out the performance hit.
It's finally here!
Every frame after commands are submitted, the system checks to see if any regions of memory are fragmented. If they are, we allocate a new block and queue up GPU-to-GPU copy commands of the resources in the fragmented block, which are added to a special command buffer that is submitted immediately. This way the copies are performed while the next frame is being built. The copies are performed sequentially into the new block, leaving no gaps. Once the next frame is submitted, we iterate over the resources that were copied and destroy them. If a block of memory is completely freed, we deallocate it.
All render targets are now allocated to dedicated memory blocks to prevent expensive copies and having to destroy and recreate a huge chain of resource dependencies.
We also now mark off partitions to include alignment offset regions to avoid tiny free regions created by alignments.
This is a very complex system and it's going to need a lot of testing, but I'm confident that this approach will reduce memory usage significantly.