6.4. Execution And Memory Dependencies

Synchronization commands introduce explicit execution and memory dependencies between two sets of action commands, where the second set of commands depends on the first set of commands. The two sets can be:

An execution dependency is a single dependency between a set of source and destination pipeline stages, which guarantees that all work performed by the set of pipeline stages included in srcStageMask (see Pipeline Stage Flags) of the first set of commands completes before any work performed by the set of pipeline stages included in dstStageMask of the second set of commands begins.

An execution dependency chain from a set of source pipeline stages $A$ to a set of destination pipeline stages $B$ is a sequence of execution dependencies submitted to a queue in order between a first set of commands and a second set of commands, satisfying the following conditions:

A pair of consecutive execution dependencies in an execution dependency chain accomplishes a dependency between the stages $A$ and $B$ via intermediate stages $C$ , even if no work is executed between them that uses the pipeline stages included in $C$ .

An execution dependency chain guarantees that the work performed by the pipeline stages $A$ in the first set of commands completes before the work performed by pipeline stages $B$ in the second set of commands begins.

A command $C_1$ is said to happen-before an execution dependency $D_2$ for a pipeline stage $S$ if all the following conditions are true:

Similarly, a command $C_2$ is said to happen-after an execution dependency $D_1$ for a pipeline stage $S$ if all the following conditions are true:

An execution dependency is by-region if its dependencyFlags parameter includes VK_DEPENDENCY_BY_REGION_BIT. Such a barrier describes a per-region (x,y,layer) dependency. That is, for each region, the implementation must ensure that the source stages for the first set of commands complete execution before any destination stages begin execution in the second set of commands for the same region. Since fragment shader invocations are not specified to run in any particular groupings, the size of a region is implementation-dependent, not known to the application, and must be assumed to be no larger than a single pixel. If dependencyFlags does not include VK_DEPENDENCY_BY_REGION_BIT, it describes a global dependency, that is for all pixel regions, the source stages must have completed for preceding commands before any destination stages starts for subsequent commands.

Memory dependencies are coupled to execution dependencies, and synchronize accesses to memory between two sets of commands. They operate according to two “halves” of a dependency to synchronize two sets of commands, the commands that happen-before the execution dependency for the srcStageMask vs the commands that happen-after the execution dependency for the dstStageMask, as described above. The first half of the dependency makes memory accesses using the set of access types in srcAccessMask performed in pipeline stages in srcStageMask by the first set of commands complete and writes be available for subsequent commands. The second half of the dependency makes any available writes from previous commands visible to pipeline stages in dstStageMask using the set of access types in dstAccessMask for the second set of commands, if those writes have been made available with the first half of the same or a previous dependency. The two halves of a memory dependency can either be expressed as part of a single command, or can be part of separate barriers as long as there is an execution dependency chain between them. The application must use memory dependencies to make writes visible before subsequent reads can rely on them, and before subsequent writes can overwrite them. Failure to do so causes the result of the reads to be undefined, and the order of writes to be undefined.

Global memory barriers apply to all resources owned by the device. Buffer and image memory barriers apply to the buffer range(s) or image subresource(s) included in the command. For accesses to a byte of a buffer or image subresource of an image to be synchronized between two sets of commands, the byte or image subresource must be included in both the first and second halves of the dependencies described above, but need not be included in each step of the execution dependency chain between them.

An execution dependency chain is by-region if all stages in all dependencies in the chain are framebuffer-space pipeline stages, and if the VK_DEPENDENCY_BY_REGION_BIT bit is included in all dependencies in the chain. Otherwise, the execution dependency chain is not by-region. The two halves of a memory dependency form a by-region dependency if all execution dependency chains between them are by-region. In other words, if there is any execution dependency between two sets of commands that is not by-region, then the memory dependency is not by-region.

When an image memory barrier includes a layout transition, the barrier first makes writes via srcStageMask and srcAccessMask available, then performs the layout transition, then makes the contents of the image subresource(s) in the new layout visible to memory accesses in dstStageMask and dstAccessMask, as if there is an execution and memory dependency between the source masks and the transition, as well as between the transition and the destination masks. Any writes that have previously been made available are included in the layout transition, but any previous writes that have not been made available may become lost or corrupt the image.

All dependencies must include at least one bit in each of the srcStageMask and dstStageMask.

Memory dependencies are used to solve data hazards, e.g. to ensure that write operations are visible to subsequent read operations (read-after-write hazard), as well as write-after-write hazards. Write-after-read and read-after-read hazards only require execution dependencies to synchronize.