6.3. Events

Events represent a fine-grained synchronization primitive that can be used to gauge progress through a sequence of commands executed on a queue by Vulkan. An event is initially in the unsignaled state. It can be signaled by a device, using commands inserted into the command buffer, or by the host. It can also be reset to the unsignaled state by a device or the host. The host can query the state of an event. A device can wait for one or more events to become signaled.

To create an event, call:

 

VkResult vkCreateEvent(
    VkDevice                                    device,
    const VkEventCreateInfo*                    pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkEvent*                                    pEvent);

The VkEventCreateInfo structure is defined as:

 

typedef struct VkEventCreateInfo {
    VkStructureType       sType;
    const void*           pNext;
    VkEventCreateFlags    flags;
} VkEventCreateInfo;

The flags member of the VkEventCreateInfo structure pointed to by pCreateInfo contains flags defining the behavior of the event. Currently, no flags are defined. When created, the event object is in the unsignaled state.

To destroy an event, call:

 

void vkDestroyEvent(
    VkDevice                                    device,
    VkEvent                                     event,
    const VkAllocationCallbacks*                pAllocator);

To query the state of an event from the host, call:

 

VkResult vkGetEventStatus(
    VkDevice                                    device,
    VkEvent                                     event);

Upon success, vkGetEventStatus returns the state of the event object with the following return codes:

Status Meaning

VK_EVENT_SET

The event specified by event is signaled.

VK_EVENT_RESET

The event specified by event is unsignaled.

The state of an event can be updated by the host. The state of the event is immediately changed, and subsequent calls to vkGetEventStatus will return the new state. If an event is already in the requested state, then updating it to the same state has no effect.

To set the state of an event to signaled from the host, call:

 

VkResult vkSetEvent(
    VkDevice                                    device,
    VkEvent                                     event);

To set the state of an event to unsignaled from the host, call:

 

VkResult vkResetEvent(
    VkDevice                                    device,
    VkEvent                                     event);

The state of an event can also be updated on the device by commands inserted in command buffers. To set the state of an event to signaled from a device, call:

 

void vkCmdSetEvent(
    VkCommandBuffer                             commandBuffer,
    VkEvent                                     event,
    VkPipelineStageFlags                        stageMask);

To set the state of an event to unsignaled from a device, call:

 

void vkCmdResetEvent(
    VkCommandBuffer                             commandBuffer,
    VkEvent                                     event,
    VkPipelineStageFlags                        stageMask);

For both vkCmdSetEvent and vkCmdResetEvent, the status of event is updated once the pipeline stages specified by stageMask (see Section 6.5.2, “Pipeline Stage Flags”) have completed executing prior commands. The command modifying the event is passed through the pipeline bound to the command buffer at time of execution.

To wait for one or more events to enter the signaled state on a device, call:

 

void vkCmdWaitEvents(
    VkCommandBuffer                             commandBuffer,
    uint32_t                                    eventCount,
    const VkEvent*                              pEvents,
    VkPipelineStageFlags                        srcStageMask,
    VkPipelineStageFlags                        dstStageMask,
    uint32_t                                    memoryBarrierCount,
    const VkMemoryBarrier*                      pMemoryBarriers,
    uint32_t                                    bufferMemoryBarrierCount,
    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
    uint32_t                                    imageMemoryBarrierCount,
    const VkImageMemoryBarrier*                 pImageMemoryBarriers);

vkCmdWaitEvents waits for events set by either vkSetEvent or vkCmdSetEvent to become signaled. Logically, it has three phases:

  1. Wait at the pipeline stages specified by dstStageMask (see Section 6.5.2, “Pipeline Stage Flags”) until the eventCount event objects specified by pEvents become signaled. Implementations may wait for each event object to become signaled in sequence (starting with the first event object in pEvents, and ending with the last), or wait for all of the event objects to become signaled at the same time.
  2. Execute the memory barriers specified by pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers (see Section 6.5.3, “Memory Barriers”).
  3. Resume execution of pipeline stages specified by dstStageMask

Implementations may not execute commands in a pipelined manner, so vkCmdWaitEvents may not observe the results of a subsequent vkCmdSetEvent or vkCmdResetEvent command, even if the stages in dstStageMask occur after the stages in srcStageMask.

Commands that update the state of events in different pipeline stages may execute out of order, unless the ordering is enforced by execution dependencies.

[Note]Note

Applications should be careful to avoid race conditions when using events. For example, an event should only be reset if no vkCmdWaitEvents command is executing that waits upon that event.

An act of setting or resetting an event in one queue may not affect or be visible to other queues. For cross-queue synchronization, semaphores can be used.