Vulkan: trouble understanding cycling of framebuff

2019-08-13 14:53发布

问题:

In Vulkan,

A semaphore(A) and a fence(X) can be passed to vkAcquireNextImageKHR. That semaphore(A) is subsequently passed to vkQueueSubmit, to wait until the image is released by the Presentation Engine (PE). A fence(Y) can also be passed to vkQueueSubmit. Client code can check when the submission has completed by checking fence(Y).

When fence(Y) signals, this means the PE can display the image.

My question:

How do I know when the PE has finished using the image after a call to vkQueuePresentKHR? To me, it doesn't seem that it would be by checking fence(X), because that is for client code to know when the image can be written to by vkQueueSubmit, isn't it? After the image is sent to vkQueueSubmit, it seems the usefulness of fence(X) is done. Or, can the same fence(X) be used to query the image availability after the call to vkQueuePresentKHR?

I don't know when the image is available again after a call to vkQueuePresentKHR, without having to call vkAcquireNextImageKHR.


The reason this is causing trouble for me is that in an asynchronous, 60fps, triple buffered app (throwaway learning code), things get out of wack like this:

  1. Send an initial framebuffer to the PE. This framebuffer is now unavailable for 16 milliseconds.
  2. Within the 16ms, acquire a second image/framebuffer, submit commands, but don't present.
  3. Do the same as #2, for a third image. We submit it before 16ms.
  4. 16ms have gone by, so we vkQueuePresentKHR the second image.
  5. Now, if I call vkAcquireNextImageKHR, the whole thing can fail if image #1 is not yet done being used, because I have acquired three images at this point.
  6. How to know if image #1 is available again without calling vkAcquireNextImageKHR?

回答1:

How do I know when the PE has finished using the image after a call to vkQueuePresentKHR?

You usually do not need to know.

Either you need to acquire a new VkImage, or you don't. Whether PE has finished or not does not even enter that decision.

Only reason wanting to know is if you want to measure presentation times. There's a special extension for that: VK_GOOGLE_display_timing.

After the image is sent to vkQueueSubmit, it seems the usefulness of fence(X) is done.

Well, you can reuse the fence. But the Implementation has stopped using it as soon as it was signaled and won't be changing its state anymore to anything, if that's what you are asking (and so you are free to vkDestroy it or do other things with it).

I don't know when the image is available again after a call to vkQueuePresentKHR, without having to call vkAcquireNextImageKHR.

Hopefully I cover it below, but I am not precisely sure what the problem here is. I don't know how to eat a soup without a spoon neither. Simply use a spoon— I mean vkAcquireNextImageKHR.

  1. Now, if I call vkAcquireNextImageKHR, the whole thing can fail if image #1 >is not yet done being used, because I have acquired 3 images at this point.
  2. How to know if image #1 is available again without calling >vkAcquireNextImageKHR?

How is it any different than image #1 and #2?

Yes, you may have already acquired all the images the swapchain has to offer, or the PE is "not ready" to give away an image even if it has two.

In the first case the spec advises against calling vkAcquireNextImageKHR with timeout of UINT64_MAX. It is a simple matter of counting the successful vkAcquireNextImageKHR calls vs the vkQueuePresentKHRs. One way may be to simply do one vkAcquireNextImageKHR and then do one vkQueuePresentKHR.

In the second case you can simply call vkAcquireNextImageKHR and you will eventually get the image.



回答2:

In order to use a swapchain image, You need to acquire it. After that the actual availability of the image for rendering purposes is signaled by the semaphore (A) or the fence (X). You can either use the semaphore (X) during the submission as a wait semaphore or wait on the CPU for the fence (X) and submit after that. For performance reasons the semaphore is a preferred way.

Now when You present an image, You give it back to the Presentation Engine. From now on You cannot use that image for whatever purposes. There is no way to check when that image is available again for You so You can render into it again. You cannot do that. If You want to render into a swapchain image again, You need to acquire another image. And during this operation You once again provide a semaphore or a fence (probably different than those provided when You previously acquired a swapchain image). There is no other way to check when an image is again available than through calling the vkAcquireNextImageKHR() function.

And when You want to implement triple-buffering, You should just select appropriate presentation mode (mailbox mode is the closest match). You shouldn't wait for a specific time before You present an image. You just should present it when You are done rendering into it. Your synchronization should be entirely based on acquire, present commands and semaphores or fences provided during these operations and during submission. Appropriate present mode should do the rest. Detailed explanation of different present modes is available in Intel's tutorial.