6

I am confused about the semantics of vkAcquireNextImageKHR. Specifically, under what circumstances can the function return VK_TIMEOUT? ie What could block it from not being able to acquire an image immediately? What might it wait for to happen?

It seems that an image can be acquired even if the presentation engine hasn't finished reading from the image, and one needs to use a semaphore or fence to synchronize usage of the acquired image anyway. What am I missing?

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319

2 Answers2

4

All of that is implementation-defined.

However, the standard gives one clear case:

An image will eventually be acquired if the number of images that the application has currently acquired (but not yet presented) is less than or equal to the difference between the number of images in swapchain and the value of VkSurfaceCapabilitiesKHR::minImageCount. If the number of currently acquired images is greater than this, vkAcquireNextImageKHR should not be called; if it is, timeout must not be UINT64_MAX.

So if you have acquired all available images in the swapchain and have not presented them, then you can get timeouts.

There may be other circumstances, but again, those are implementation-defined. A perfectly valid implementation of vkAcquireNextImageKHR can signal the semaphore/fence that you provide before it returns a successful acquisition, thus forcing any delay into the vkAcquireNextImageKHR call itself. You have no control over this.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • (1) This doesn't really answer the question. What specifically are some examples of the circumstances in production implementations? For what purpose was this timeout facility designed into vulkan for in the first place? (2) I don't believe it was just to limit the number of simulatenously acquired images, the host can surely track and limit that itself, and as per the quote, it *should not* be used for that. (3) I also don't think the hypothetical scenario given last is actually present in any production implementations right? It's contrived to illustrate the boundary of the contract. – Andrew Tomazos Oct 05 '18 at 18:06
  • @AndrewTomazos: Those circumstances could change *tomorrow*. It's implementation-dependent. "*the host can surely track and limit that itself*" Sure. But the specification has to say what happens if you do over-acquire. Hence, this is a case where the timeout can come into effect. "*I also don't think the hypothetical scenario given last is actually present in any production implementations right?*" I don't know that it is or isn't. My point is that it *could be*, so you have to respect the possibility of it. Don't code in a way that relies on implementation-defined behavior. – Nicol Bolas Oct 05 '18 at 18:10
  • My question is, essentially, what was the facility designed for? I don't think you know the answer to that, which is of course fine. – Andrew Tomazos Oct 05 '18 at 18:23
  • @AndrewTomazos: Well, that's not what you asked, and the only people who could answer that are the Khronos Group. My guess is that it exists to allow implementations freedom. Vulkan needs to be able to run on a *lot* of platforms. It's not like Metal or Direct3D 12, where they can just pick-and-choose which OS, compositor, and hardware to support. Giving implementations flexibility, *especially* when it comes to presentation (which interacts with the OS, GUI, compositor, and other things), ensures that implementers can implement Vulkan on pretty much anything. – Nicol Bolas Oct 05 '18 at 18:28
4

Nicol Bolas's answer is correct, but since the responses to it asked for details about where this is used in real implementations I'll add another answer here.

On Android, vkQueuePresentKHR sends the image to the compositor (SurfaceFlinger), which displays it. The compositor re-displays this image on every display refresh until it gets a new image to display for that window. Until it gets that next image, it doesn't know whether or how many times it will need to read the buffer again in the future, and can't create a semaphore that will signal when the last read completes. (Hypothetically, you could build a system that could do that, but that's not how the Linux kernel sync mechanisms Android uses for this work.) So until you present image N+1, the compositor can't release image N back to your app for it to acquire, since it can't give you a semaphore to go along with it.

It's a little more complicated than that, since even if you present frame N+1, the compositor doesn't know how long it will take until the rendering semaphore signals, so it still doesn't know immediately how much longer it will need to be able to read the image for frame N.

This extends to swapchains with more than two buffers.

I'm not as familiar with other systems, but I believe others have similar constraints that prevent them from allowing you to acquire images arbitrarily far ahead of presenting them. It's definitely possible to build a presentation engine that would allow that, but Vulkan needed to work on existing systems and existing presentation engines, so had to live with the restrictions those existing systems impose. Khronos members can't change the Windows compositor, and others like X11, Wayland, and Android are difficult/slow to change since doing so could impact all existing apps, frameworks, etc.

Jesse Hall
  • 6,441
  • 23
  • 29