# Queue Present Wait Semaphore Management The following shorthand notations are used throughout this document: - PE: Presentation Engine - ANI: vkAcquireNextImageKHR - QS: vkQueueSubmit - QP: vkQueuePresentKHR - W: Wait - S: Signal - R: Render - P: Present - SN: Semaphore N - IN: Swapchain image N --- ## Introduction Vulkan requires the application (ANGLE in this case) to acquire swapchain images and queue them for presentation, synchronizing GPU submissions with semaphores. A single frame looks like the following: CPU: ANI ... QS ... QP S:S1 W:S1 W:S2 S:S2 GPU: <------------ R -----------> PE: <-------- P ------> That is, the GPU starts rendering after submission, and the presentation is started when rendering is finished. Note that Vulkan tries to abstract a large variety of PE architectures, some of which do not behave in a straight-forward manner. As such, ANGLE cannot know what the PE is exactly doing with the images or when the images are visible on the screen. The only signal out of the PE is received through the semaphore and fence that's used in ANI. The issue is that, in the above diagram, it's unclear when S2 can be destroyed or recycled. That happens when rendering (R) is finished and before present (P) starts. As a result, this time has to be inferred by a future operation. ## Determining When a QP Semaphore is Waited On The ANI call takes a semaphore, that is signaled once the image is acquired. When that happens, it can be inferred that the previous presentation of the image is done, which in turn implies that its associated wait semaphore is no longer in use. Assuming both ANI calls below return the same index: CPU: ANI ... QS ... QP ANI ... QS ... QP S:S1 W:S1 W:S2 S:S3 W:S3 W:S4 S:S2 S:S4 GPU: <------ R ------> <------ R ------> PE: <-- P --> <-- P --> The following holds: S3 is signaled => The PE has handed the image to the application => The PE is no longer presenting the image (the first P operation is finished) => The PE is done waiting on S2 At this point, we can destroy or recycle S2. To implement this, a history of present operations is maintained, which includes the wait semaphore used with that presentation. Associated with each present operation, is a QueueSerial that is used to determine when that semaphore can be destroyed. This QueueSerial has execution dependency on the ANI semaphore (QS W:S3 in the above diagram). Since the QueueSerial is not actually known at present time (QP), the present operation is kept in history without an associated QueueSerial. Once same index is presented again, the QueueSerial of QS before QP is associated with the previous QP of that index. At each present call, the present history is inspected. Any present operation whose QueueSerial is finished is cleaned up. ANI fence cannot always be used instead of QueueSerial with dependency on ANI semaphore. This is because with Shared Present mode, the fence and semaphore are expected to be already signaled on the second and later ANI calls. ## Swapchain recreation When recreating the swapchain, all images are eventually freed and new ones are created, possibly with a different count and present mode. For the old swapchain, we can no longer rely on a future ANI to know when a previous presentation's semaphore can be destroyed, as there won't be any more acquisitions from the old swapchain. Similarly, we cannot know when the old swapchain itself can be destroyed. ANGLE resolves this issue by deferring the destruction of the old swapchain and its remaining present semaphores to the time when the semaphore corresponding to the first present of the new swapchain can be destroyed. Because once the first present semaphore of the new swapchain can be destroyed, the first present operation of the new swapchain is done, which means the old swapchain is no longer being presented. Note that the swapchain may be recreated without a second acquire. This means that the swapchain could be recreated while there are pending old swapchains to be destroyed. The destruction of both old swapchains must now be deferred to when the first QP of the new swapchain has been processed. If an application resizes the window constantly and at a high rate, ANGLE would keep accumulating old swapchains and not free them until it stops. ## VK_EXT_swapchain_maintenance1 With the VK_EXT_swapchain_maintenance1, all the above is unnecessary. Each QP operation can have an associated fence, which can be used to know when the semaphore associated with it can be recycled. The old swapchains are destroyed when QP fences are signaled.