vkQueuePresentKHR / presentKHR without fence doesn't make sense! ;-)

Following concern is probably related to https://github.com/KhronosGroup/Vulkan-Docs/issues/370

There is currently no way to query if WaitSemaphores, passed via VkPresentInfoKHR to vkQueuePresentKHR, are ready to be re-used (i.e. are set back to UNSIGNALED state).
The UNSIGNALED state is a requirement when passing SignalSemaphores to functions
like acquireNextImageKHR() or vkQueueSubmit().

Even when preallocating swapchain-image-count semaphores, it could in theory happen
that a semaphore was not yet set back to UNSIGNALED state before re-using it when no
device/queue waitIdle() is used between frames.

While for the acquireNextImageKHR semaphore it is possible to guarantee the UNSIGNALED
state by waiting for the command buffer submit fence from some older frame (ring buffer approach),
there is no elegant way for the semaphores used for signaling submit completion or finished image
ownership transfer to a separate present queue.

So I was wondering what is the best solution. Is it expensive to just create new semaphores
every frame? Currently my workaround is to preallocate a bit more than “swapchain-image-count”
semaphores and rely on the command buffer fences to throttle when too many frames pile up.

If vkQueuePresentKHR would offer a fence that could be used to check if a frame was actually
presented on screen that would also allow to guarantee that all semaphores from a past frame
are ready to be re-used.

Is there some reason why you can’t just do the obvious and use a fence? This is a “problem” created by the unwillingness to use a fence. So just do that.

That should be fine. What’s the problem?

Also, timeline semaphores can be employed if those are available to you.

So would testing the acquire fence. If an image that was previously presented has been acquired, then its present operation has completed. Indeed, the standard specifically says:

applications can use fence to meter their frame generation work to match the presentation rate.

That includes semaphores.

Indeed, testing any fence for a queue operation that is itself dependent on the acquire (via a semaphore) would also work.

That’s exactly my point in the title, in contrast to acquireNextImageKHR() the presentKHR() function does NOT accept a fence. I would love to use a fence so there is no “unwillingness” but a lack of possibility.

It’s not a problem. I could live with that workaround but always try to avoid workarounds so when looking some years later into code there are less quirks to recap.

Afaik acquireNextImageKHR and presentKHR only accept semaphores of type VK_SEMAPHORE_TYPE_BINARY.

Yes, this is basically what my workaround implicitly relies on (the queue submit fences which
are throttling when “swapchain-image-count”-frames have piled up). But maybe I will make it
more explicit by using acquired fences.

Something that makes the whole thing a bit tricky is that acquireNextImageKHR could return any
RANDOM swapchain image index so you only know the next index after calling it while you have
to select a “free” semaphore index before calling it.

What’s the difference between checking if present has finished vs. checking if acquire has finished? You mention at the end that it’s “a bit tricky” because you can’t pair an image index with a semaphore, but all that means is that you need N+1 semaphores in a simple pool. When you acquire an image, you pick an unused semaphore out of the pool. When you test the acquire-fence, you put the presented semaphore back into the pool.

I did not know that.