Fences are a synchronization primitive that can be used to insert a
dependency from a queue to the host.
Fences have two states - signaled and unsignaled.
A fence can be signaled as part of the execution of a
queue submission command.
Fences can be unsignaled on the host with vkResetFences
.
Fences can be waited on by the host with the vkWaitForFences
command,
and the current state can be queried with vkGetFenceStatus
.
Fences are represented by VkFence
handles:
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence)
To create a fence, call:
VkResult vkCreateFence( VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
device
is the logical device that creates the fence.
pCreateInfo
is a pointer to an instance of the
VkFenceCreateInfo
structure which contains information about how
the fence is to be created.
pAllocator
controls host memory allocation as described in the
Memory Allocation chapter.
pFence
points to a handle in which the resulting fence object is
returned.
The VkFenceCreateInfo
structure is defined as:
typedef struct VkFenceCreateInfo { VkStructureType sType; const void* pNext; VkFenceCreateFlags flags; } VkFenceCreateInfo;
sType
is the type of this structure.
pNext
is NULL
or a pointer to an extension-specific structure.
flags
defines the initial state and behavior of the fence.
Bits which can be set include:
typedef enum VkFenceCreateFlagBits { VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, } VkFenceCreateFlagBits;
If flags
contains VK_FENCE_CREATE_SIGNALED_BIT
then the fence
object is created in the signaled state; otherwise it is created in the
unsignaled state.
To destroy a fence, call:
void vkDestroyFence( VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);
device
is the logical device that destroys the fence.
fence
is the handle of the fence to destroy.
pAllocator
controls host memory allocation as described in the
Memory Allocation chapter.
To query the status of a fence from the host, call:
VkResult vkGetFenceStatus( VkDevice device, VkFence fence);
device
is the logical device that owns the fence.
fence
is the handle of the fence to query.
Upon success, vkGetFenceStatus
returns the status of the fence object,
with the following return codes:
Table 6.3. Fence Object Status Codes
Status | Meaning |
---|---|
| The fence specified by |
| The fence specified by |
If a queue submission command is pending execution, then the value returned by this command may immediately be out of date.
To set the state of fences to unsignaled from the host, call:
VkResult vkResetFences( VkDevice device, uint32_t fenceCount, const VkFence* pFences);
device
is the logical device that owns the fences.
fenceCount
is the number of fences to reset.
pFences
is a pointer to an array of fence handles to reset.
When vkResetFences
is executed on the host, it defines a fence
unsignal operation for each fence, which resets the fence to the unsignaled
state.
If any member of pFences
is already in the unsignaled state when
vkResetFences
is executed, then vkResetFences
has no effect on
that fence.
When a fence is submitted to a queue as part of a queue submission command, it defines a memory dependency on the batches that were submitted as part of that command, and defines a fence signal operation which sets the fence to the signaled state.
The first synchronization scope
includes every batch submitted in the same queue submission command.
Fence signal operations that are defined by vkQueueSubmit
additionally
include all previous queue submissions to the same queue via
vkQueueSubmit
in the first synchronization scope.
The second synchronization scope only includes the fence signal operation.
The first access scope includes all memory access performed by the device.
The second access scope is empty.
To wait for one or more fences to enter the signaled state on the host, call:
VkResult vkWaitForFences( VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);
device
is the logical device that owns the fences.
fenceCount
is the number of fences to wait on.
pFences
is a pointer to an array of fenceCount
fence
handles.
waitAll
is the condition that must be satisfied to successfully
unblock the wait.
If waitAll
is VK_TRUE
, then the condition is that all fences
in pFences
are signaled.
Otherwise, the condition is that at least one fence in pFences
is
signaled.
timeout
is the timeout period in units of nanoseconds.
timeout
is adjusted to the closest value allowed by the
implementation-dependent timeout accuracy, which may be substantially
longer than one nanosecond, and may be longer than the requested
period.
If the condition is satisfied when vkWaitForFences
is called, then
vkWaitForFences
returns immediately.
If the condition is not satisfied at the time vkWaitForFences
is
called, then vkWaitForFences
will block and wait up to timeout
nanoseconds for the condition to become satisfied.
If timeout
is zero, then vkWaitForFences
does not wait, but
simply returns the current state of the fences.
VK_TIMEOUT
will be returned in this case if the condition is not
satisfied, even though no actual wait was performed.
If the specified timeout period expires before the condition is satisfied,
vkWaitForFences
returns VK_TIMEOUT
.
If the condition is satisfied before timeout
nanoseconds has expired,
vkWaitForFences
returns VK_SUCCESS
.
An execution dependency is defined by waiting for a fence to become
signaled, either via vkWaitForFences
or by polling on
vkGetFenceStatus
.
The first synchronization scope includes only the fence signal operation.
The second synchronization scope
includes the host operations of vkWaitForFences
or
vkGetFenceStatus
indicating that the fence has become signaled.
![]() | Note |
---|---|
Signaling a fence and waiting on the host does not guarantee that the
results of memory accesses will be visible to the host.
To provide that guarantee, the application must insert a memory barrier
between the device writes and the end of the submission that will signal the
fence, with |