Semaphores are a synchronization primitive that can be used to insert a dependency between batches submitted to queues. Semaphores have two states - signaled and unsignaled. The state of a semaphore can be signaled after execution of a batch of commands is completed. A batch can wait for a semaphore to become signaled before it begins execution, and the semaphore is also unsignaled before the batch begins execution.
Semaphores are represented by VkSemaphore
handles:
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore)
To create a semaphore, call:
VkResult vkCreateSemaphore( VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore);
device
is the logical device that creates the semaphore.
pCreateInfo
is a pointer to an instance of the
VkSemaphoreCreateInfo
structure which contains information about
how the semaphore is to be created.
pAllocator
controls host memory allocation as described in the
Memory Allocation chapter.
pSemaphore
points to a handle in which the resulting semaphore
object is returned.
When created, the semaphore is in the unsignaled state.
The VkSemaphoreCreateInfo
structure is defined as:
typedef struct VkSemaphoreCreateInfo { VkStructureType sType; const void* pNext; VkSemaphoreCreateFlags flags; } VkSemaphoreCreateInfo;
sType
is the type of this structure.
pNext
is NULL
or a pointer to an extension-specific structure.
flags
is reserved for future use.
To destroy a semaphore, call:
void vkDestroySemaphore( VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);
device
is the logical device that destroys the semaphore.
semaphore
is the handle of the semaphore to destroy.
pAllocator
controls host memory allocation as described in the
Memory Allocation chapter.
When a batch is submitted to a queue via a queue submission, and it includes semaphores to be signaled, it defines a memory dependency on the batch, and defines semaphore signal operations which set the semaphores to the signaled state.
The first synchronization scope
includes every command submitted in the same batch.
Semaphore signal operations that are defined by vkQueueSubmit
additionally include all batches previously submitted to the same queue via
vkQueueSubmit
, including batches that are submitted in the same
queue submission command, but at a lower index
within the array of batches.
The second synchronization scope includes only the semaphore signal operation.
The first access scope includes all memory access performed by the device.
The second access scope is empty.
When a batch is submitted to a queue via a queue submission, and it includes semaphores to be waited on, it defines a memory dependency between prior semaphore signal operations and the batch, and defines semaphore unsignal operations which set the semaphores to the unsignaled state.
The first synchronization scope includes all semaphore signal operations that operate on semaphores waited on in the same batch, and that happen-before the wait completes.
The second synchronization scope
includes every command submitted in the same batch.
In the case of vkQueueSubmit
, the second synchronization scope is
limited to operations on the pipeline stages determined by the
destination stage mask specified
by the corresponding element of pWaitDstStageMask
.
Also, in the case of vkQueueSubmit
, the second synchronization scope
additionally includes all batches subsequently submitted to the same queue
via vkQueueSubmit
, including batches that are submitted in the same
queue submission command, but at a higher
index within the array of batches.
The first access scope is empty.
The second access scope includes all memory access performed by the device.
The semaphore unsignal operation happens-after the first set of operations in the execution dependency, and happens-before the second set of operations in the execution dependency.
![]() | Note |
---|---|
Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore. If two operations are separately specified to wait for the same semaphore, and there are no other execution dependencies between those operations, behaviour is undefined. An execution dependency must be present that guarantees that the semaphore unsignal operation for the first of those waits, happens-before the semaphore is signalled again, and before the second unsignal operation. Semaphore waits and signals should thus occur in discrete 1:1 pairs. |
![]() | Note |
---|---|
A common scenario for using If an image layout transition needs to be performed on a swapchain image
before it is used in a framebuffer, that can be performed as the first
operation submitted to the queue after acquiring the image, and should not
prevent other work from overlapping with the presentation operation.
For example, a
Alternatively, This barrier accomplishes a dependency chain between previous presentation
operations and subsequent color attachment output operations, with the
layout transition performed in between, and does not introduce a dependency
between previous work and any vertex processing stages.
More precisely, the semaphore signals after the presentation operation
completes, then the semaphore wait stalls the
|