Fences can be used by the host to determine completion of execution of queue operations.
A fence’s status is always either signaled or unsignaled. The host can poll the status of a single fence, or wait for any or all of a group of fences to become signaled.
Fences are represented by VkFence handles:
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence)
To create a new fence object, use the command
VkResult vkCreateFence(
VkDevice device,
const VkFenceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkFence* pFence);
device is the logical device that creates the fence.
pCreateInfo points to a VkFenceCreateInfo structure
specifying the state of the fence object.
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;
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, use the command
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,
which is one of:
VK_SUCCESS indicates that the fence is signaled.
VK_NOT_READY indicates that the fence is unsignaled.
To reset the status of one or more fences to the unsignaled state, use the command:
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 fenceCount fence
handles to reset.
If a fence is already in the unsignaled state, then resetting it has no effect.
Fences can be signaled by including them in a
queue submission command, defining a
queue operation to signal that fence.
This fence signal operation defines the first half of a memory dependency,
guaranteeing that all memory accesses defined by the queue submission are
made available, and that queue operations described by that submission have
completed execution.
This half of the memory dependency does not include host availability of
memory accesses.
The second half of the dependency can be defined by vkWaitForFences.
Fence signal operations for vkQueueSubmit additionally include all
queue operations previously submitted via vkQueueSubmit in their half
of a memory dependency.
To cause the host to wait until any one or all of a group of fences is signaled, use the command:
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.
vkWaitForFences defines the second half of a memory dependency with
the host, for each fence being waited on. The memory dependency defined by
signaling a fence and waiting on the host does not guarantee that the
results of memory accesses will be visible to the host, or that the memory
is available. 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 dstAccessMask having the
VK_ACCESS_HOST_READ_BIT bit set, with dstStageMask having the
VK_PIPELINE_STAGE_HOST_BIT bit set, and with the appropriate
srcStageMask and srcAccessMask members set to guarantee
completion of the writes. If the memory was allocated without the
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT set, then
vkInvalidateMappedMemoryRanges must be called after the fence is
signaled in order to ensure the writes are visible to the host, as described
in Host Access to Device Memory Objects.