# 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_KHR_swapchain_maintenance1 / VK_EXT_swapchain_maintenance1

With the VK_KHR_swapchain_maintenance1 or VK_EXT_swapchain_maintenance1 extension, 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.
