openlang

Who owns a Vulkan buffer after submission?

A C++ RAII wrapper around a Vulkan buffer records work that uses the buffer, submits it, and goes out of scope. Its destructor calls vkDestroyBuffer right there. The submitted commands that refer to the buffer are still executing.

That call is invalid. Vulkan requires every submitted command referring to the buffer to have completed execution before the buffer is destroyed. Scope exit only shows that the host is finished with the wrapper. It shows nothing about the GPU.

My first idea is to move the wrapper into a frame retirement list at submission and destroy it only after completion of that submission is known. What I keep going back and forth on is where the move belongs. Inside the submit call? In whatever owns the frame? And calling it a frame list doesn't answer when an entry is actually allowed to go.

The conversation continues 3

Follow the reasoning
  1. Permalink

    One release owner, named. Someone removes the entry once completion is known, and someone keeps it if the host operation exits early. Those may be the same component, but the design should say which. Setting the wrapper's local pointer to null changes that variable and nothing else. It frees nothing and says nothing about whether the submitted commands have finished.

  2. Permalink

    Check where the retirement list itself lives. If its entries sit in temp storage that gets cleared at frame end while their buffers still wait on the GPU, the entries are gone before they've done their job. In Odin that means looking at which allocator the dynamic array recorded, not which one the context holds at submit time.

  3. Permalink

    If the transfer is a move into the retirement list, the wrapper's move constructor has to leave the source owning nothing, so that its destructor does nothing. Usually that means writing VK_NULL_HANDLE into the moved-from object and checking for it in the destructor. Skip that and the local still destroys the buffer at scope exit, now with a second owner sitting in the list.

    Moved-from objects are still destroyed. The standard's "valid but unspecified state" covers library types only. For your own wrapper, moved-from means whatever your move constructor writes, and nothing else.

Other sides of the same question

  1. Signals fire right now, not at the end of the frame

    This one bit me in Godot and seems to bite everyone eventually. emit_signal() and signal.emit() call the connected functions…