I'm starting to think about some of the issues involved in incorporating Vulkan into an engine. If I understand correctly, it's not safe to destroy a device memory resource while it's still referenced by a command buffer. In other words, Vulkan doesn't do any internal reference counting, and so a destroy operation will take effect immediately, even if the GPU is currently using the resource (or will do so in the near future).
Obviously the goal of this design approach was to allow engine builders to roll special case solutions for this. So I was wondering what approaches people were taking to deal with this problem?
I've run across this before, when implementing a PS3 version of an engine that was designed for DX9. The engine assumed that it could destroy GPU resources safely at any time (which is true for DX9). So, for my low level PS3 code, I had to provide the same guarantees.
To do this, I kept a list of referenced resources long with each command buffer. Periodically, I checked for completed command buffers, and could dereference the associated resource.
My goal was to reduce the cost in the most common case (ie, nothing being destroyed) to as little as possible. This solution was ok, but was a little awkward because the list of resources could get quite long. And (in that particular engine) some resources tended to be referenced many times by the same list; so I actually ended up sorting the list to avoid adding duplicates. That worked well, because it duplicated the kind of behaviour we expected from DX9.
Another option might be to group related resources together into a "box"... We could then do reference counting on the entire box, so that all contained resources get destroyed together. It would require some extra structure in the engine, but might reduce the low level overhead. That would be handy for streaming in and out character models -- where multiple resources will typically be evicted at the same time.
Another possibility would be to always delay any resource deallocation until all active command buffers have completed (regardless of whether it's actually referenced). It other words, we could assume that all resources are referenced by all command buffers... That would introduce the absolute minimal overhead in the normal case. But it would mean that deallocation never completes rapidly. It would also cause problems if even a single command buffer isn't promptly ended and submitted.
What approaches are people here taking for this issue?