| /* |
| * Copyright © 2021 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| * IN THE SOFTWARE. |
| */ |
| #ifndef VK_SYNC_H |
| #define VK_SYNC_H |
| |
| #include <stdbool.h> |
| #include <vulkan/vulkan_core.h> |
| |
| #include "util/macros.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| struct vk_device; |
| struct vk_sync; |
| |
| enum vk_sync_features { |
| /** Set if a sync type supports the binary mode of operation |
| * |
| * In binary mode, a vk_sync has two modes: signaled and unsignaled. If |
| * it supports CPU_RESET, it can be changed from signaled to unsignaled on |
| * the CPU via vk_sync_reset(). If it supports CPU_SIGNAL, it can be |
| * changed from unsignaled to signaled on the CPU via vk_sync_signal(). |
| * |
| * Binary vk_sync types may also support WAIT_PENDING in which they have a |
| * third hidden pending state. Once such a vk_sync has been submitted to |
| * the kernel driver for signaling, it is in the pending state and remains |
| * there until the work is complete at which point it enters the signaled |
| * state. This pending state is visible across processes for shared |
| * vk_sync types. This is used to by the threaded submit mode to ensure |
| * that everything gets submitted to the kernel driver in-order. |
| * |
| * A vk_sync operates in binary mode if VK_SYNC_IS_TIMELINE is not set |
| * in vk_sync::flags. |
| */ |
| VK_SYNC_FEATURE_BINARY = (1 << 0), |
| |
| /** Set if a sync type supports the timeline mode of operation |
| * |
| * In timeline mode, a vk_sync has a monotonically increasing 64-bit value |
| * which represents most recently signaled time point. Waits are relative |
| * to time points. Instead of waiting for the vk_sync to enter a signaled |
| * state, you wait for its 64-bit value to be at least some wait value. |
| * |
| * Timeline vk_sync types can also support WAIT_PENDING. In this case, the |
| * wait is not for a pending state, as such, but rather for someone to have |
| * submitted a kernel request which will signal a time point with at least |
| * that value. Logically, you can think of this as having two timelines, |
| * the real timeline and a pending timeline which runs slightly ahead of |
| * the real one. As with binary vk_sync types, this is used by threaded |
| * submit to re-order things so that the kernel requests happen in a valid |
| * linear order. |
| * |
| * A vk_sync operates in timeline mode if VK_SYNC_IS_TIMELINE is set in |
| * vk_sync::flags. |
| */ |
| VK_SYNC_FEATURE_TIMELINE = (1 << 1), |
| |
| /** Set if this sync supports GPU waits */ |
| VK_SYNC_FEATURE_GPU_WAIT = (1 << 2), |
| |
| /** Set if a sync type supports multiple GPU waits on one signal state |
| * |
| * The Vulkan spec for VkSemaphore requires GPU wait and signal operations |
| * to have a one-to-one relationship. This formally described by saying |
| * that the VkSemaphore gets implicitly reset on wait. However, it is |
| * often useful to have well-defined multi-wait. If binary vk_sync |
| * supports multi-wait then any number of kernel requests can be submitted |
| * which wait on one signal operation. This also implies that you can |
| * signal twice back-to-back (there are 0 waits on the first signal). |
| * |
| * This feature only applies to binary vk_sync objects. |
| */ |
| VK_SYNC_FEATURE_GPU_MULTI_WAIT = (1 << 3), |
| |
| /** Set if a sync type supports vk_sync_wait() and vk_sync_wait_many() */ |
| VK_SYNC_FEATURE_CPU_WAIT = (1 << 4), |
| |
| /** Set if a sync type supports vk_sync_reset() |
| * |
| * This feature only applies to binary vk_sync objects. |
| */ |
| VK_SYNC_FEATURE_CPU_RESET = (1 << 5), |
| |
| /** Set if a sync type supports vk_sync_signal() */ |
| VK_SYNC_FEATURE_CPU_SIGNAL = (1 << 6), |
| |
| /** Set if sync_type::wait_many supports the VK_SYNC_WAIT_ANY bit |
| * |
| * vk_sync_wait_many() will support the bit regardless. If the sync type |
| * doesn't support it natively, it will be emulated. |
| */ |
| VK_SYNC_FEATURE_WAIT_ANY = (1 << 7), |
| |
| /** Set if a sync type supports the VK_SYNC_WAIT_PENDING bit |
| * |
| * See VK_SYNC_FEATURE_BINARY and VK_SYNC_FEATURE_TIMELINE for descriptions |
| * of what this does in each case. |
| */ |
| VK_SYNC_FEATURE_WAIT_PENDING = (1 << 8), |
| |
| /** Set if a sync type natively supports wait-before-signal |
| * |
| * If this is set then the underlying OS primitive supports submitting |
| * kernel requests which wait on the vk_sync before submitting a kernel |
| * request which would cause that wait to unblock. |
| */ |
| VK_SYNC_FEATURE_WAIT_BEFORE_SIGNAL = (1 << 9), |
| }; |
| |
| struct vk_sync_wait; |
| |
| enum vk_sync_wait_flags { |
| /** Placeholder for 0 to make vk_sync_wait() calls more clear */ |
| VK_SYNC_WAIT_COMPLETE = 0, |
| |
| /** If set, only wait for the vk_sync operation to be pending |
| * |
| * See VK_SYNC_FEATURE_BINARY and VK_SYNC_FEATURE_TIMELINE for descriptions |
| * of what this does in each case. |
| */ |
| VK_SYNC_WAIT_PENDING = (1 << 0), |
| |
| /** If set, wait for any of of the vk_sync operations to complete |
| * |
| * This is as opposed to waiting for all of them. There is no guarantee |
| * that vk_sync_wait_many() will return immediately after the first |
| * operation completes but it will make a best effort to return as soon as |
| * possible. |
| */ |
| VK_SYNC_WAIT_ANY = (1 << 1), |
| }; |
| |
| struct vk_sync_type { |
| /** Size of this sync type */ |
| size_t size; |
| |
| /** Features supported by this sync type */ |
| enum vk_sync_features features; |
| |
| /** Initialize a vk_sync |
| * |
| * The base vk_sync will already be initialized and the sync type set |
| * before this function is called. If any OS primitives need to be |
| * allocated, that should be done here. |
| */ |
| VkResult (*init)(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t initial_value); |
| |
| /** Finish a vk_sync |
| * |
| * This should free any internal data stored in this vk_sync. |
| */ |
| void (*finish)(struct vk_device *device, |
| struct vk_sync *sync); |
| |
| /** Signal a vk_sync |
| * |
| * For non-timeline sync types, value == 0. |
| */ |
| VkResult (*signal)(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t value); |
| |
| /** Get the timeline value for a vk_sync */ |
| VkResult (*get_value)(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t *value); |
| |
| /** Reset a non-timeline vk_sync */ |
| VkResult (*reset)(struct vk_device *device, |
| struct vk_sync *sync); |
| |
| /** Moves the guts of one binary vk_sync to another |
| * |
| * This moves the current binary vk_sync event from src to dst and resets |
| * src. If dst contained an event, it is discarded. |
| * |
| * This is required for all binary vk_sync types that can be used for a |
| * semaphore wait in conjunction with real timeline semaphores. |
| */ |
| VkResult (*move)(struct vk_device *device, |
| struct vk_sync *dst, |
| struct vk_sync *src); |
| |
| /** Wait on a vk_sync |
| * |
| * For a timeline vk_sync, wait_value is the timeline value to wait for. |
| * This function should not return VK_SUCCESS until get_value on that |
| * vk_sync would return a value >= wait_value. A wait_value of zero is |
| * allowed in which case the wait is a no-op. For a non-timeline vk_sync, |
| * wait_value should be ignored. |
| * |
| * This function is optional. If the sync type needs to support CPU waits, |
| * at least one of wait or wait_many must be provided. If one is missing, |
| * it will be implemented in terms of the other. |
| */ |
| VkResult (*wait)(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t wait_value, |
| enum vk_sync_wait_flags wait_flags, |
| uint64_t abs_timeout_ns); |
| |
| /** Wait for multiple vk_sync events |
| * |
| * If VK_SYNC_WAIT_ANY is set, it will return after at least one of the |
| * wait events is complete instead of waiting for all of them. |
| * |
| * See wait for more details. |
| */ |
| VkResult (*wait_many)(struct vk_device *device, |
| uint32_t wait_count, |
| const struct vk_sync_wait *waits, |
| enum vk_sync_wait_flags wait_flags, |
| uint64_t abs_timeout_ns); |
| |
| /** Permanently imports the given FD into this vk_sync |
| * |
| * This replaces the guts of the given vk_sync with whatever is in the FD. |
| * In a sense, this vk_sync now aliases whatever vk_sync the FD was |
| * exported from. |
| */ |
| VkResult (*import_opaque_fd)(struct vk_device *device, |
| struct vk_sync *sync, |
| int fd); |
| |
| /** Export the guts of this vk_sync to an FD */ |
| VkResult (*export_opaque_fd)(struct vk_device *device, |
| struct vk_sync *sync, |
| int *fd); |
| |
| /** Imports a sync file into this binary vk_sync |
| * |
| * If this completes successfully, the vk_sync will now signal whenever |
| * the sync file signals. |
| * |
| * If sync_file == -1, the vk_sync should be signaled immediately. If |
| * the vk_sync_type implements signal, sync_file will never be -1. |
| */ |
| VkResult (*import_sync_file)(struct vk_device *device, |
| struct vk_sync *sync, |
| int sync_file); |
| |
| /** Exports the current binary vk_sync state as a sync file. |
| * |
| * The resulting sync file will contain the current event stored in this |
| * binary vk_sync must be turned into a sync file. If the vk_sync is later |
| * modified to contain a new event, the sync file is unaffected. |
| */ |
| VkResult (*export_sync_file)(struct vk_device *device, |
| struct vk_sync *sync, |
| int *sync_file); |
| |
| #if defined(USE_MAGMA) |
| VkResult (*import_magma_handle)(struct vk_device *device, |
| struct vk_sync *sync, |
| uint32_t handle); |
| |
| VkResult (*export_magma_handle)(struct vk_device *device, |
| struct vk_sync *sync, |
| uint32_t* handle_out); |
| #endif |
| }; |
| |
| enum vk_sync_flags { |
| /** Set if the vk_sync is a timeline */ |
| VK_SYNC_IS_TIMELINE = (1 << 0), |
| |
| /** Set if the vk_sync can have its payload shared */ |
| VK_SYNC_IS_SHAREABLE = (1 << 1), |
| |
| /** Set if the vk_sync has a shared payload */ |
| VK_SYNC_IS_SHARED = (1 << 2), |
| }; |
| |
| struct vk_sync { |
| const struct vk_sync_type *type; |
| enum vk_sync_flags flags; |
| }; |
| |
| /* See VkSemaphoreSubmitInfo */ |
| struct vk_sync_wait { |
| struct vk_sync *sync; |
| VkPipelineStageFlags2 stage_mask; |
| uint64_t wait_value; |
| }; |
| |
| /* See VkSemaphoreSubmitInfo */ |
| struct vk_sync_signal { |
| struct vk_sync *sync; |
| VkPipelineStageFlags2 stage_mask; |
| uint64_t signal_value; |
| }; |
| |
| VkResult MUST_CHECK vk_sync_init(struct vk_device *device, |
| struct vk_sync *sync, |
| const struct vk_sync_type *type, |
| enum vk_sync_flags flags, |
| uint64_t initial_value); |
| |
| void vk_sync_finish(struct vk_device *device, |
| struct vk_sync *sync); |
| |
| VkResult MUST_CHECK vk_sync_create(struct vk_device *device, |
| const struct vk_sync_type *type, |
| enum vk_sync_flags flags, |
| uint64_t initial_value, |
| struct vk_sync **sync_out); |
| |
| void vk_sync_destroy(struct vk_device *device, |
| struct vk_sync *sync); |
| |
| VkResult MUST_CHECK vk_sync_signal(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t value); |
| |
| VkResult MUST_CHECK vk_sync_get_value(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t *value); |
| |
| VkResult MUST_CHECK vk_sync_reset(struct vk_device *device, |
| struct vk_sync *sync); |
| |
| VkResult MUST_CHECK vk_sync_wait(struct vk_device *device, |
| struct vk_sync *sync, |
| uint64_t wait_value, |
| enum vk_sync_wait_flags wait_flags, |
| uint64_t abs_timeout_ns); |
| |
| VkResult MUST_CHECK vk_sync_wait_many(struct vk_device *device, |
| uint32_t wait_count, |
| const struct vk_sync_wait *waits, |
| enum vk_sync_wait_flags wait_flags, |
| uint64_t abs_timeout_ns); |
| |
| VkResult MUST_CHECK vk_sync_import_opaque_fd(struct vk_device *device, |
| struct vk_sync *sync, |
| int fd); |
| |
| VkResult MUST_CHECK vk_sync_export_opaque_fd(struct vk_device *device, |
| struct vk_sync *sync, |
| int *fd); |
| |
| VkResult MUST_CHECK vk_sync_import_sync_file(struct vk_device *device, |
| struct vk_sync *sync, |
| int sync_file); |
| |
| VkResult MUST_CHECK vk_sync_export_sync_file(struct vk_device *device, |
| struct vk_sync *sync, |
| int *sync_file); |
| |
| #if defined(USE_MAGMA) |
| VkResult MUST_CHECK vk_sync_import_magma_handle(struct vk_device *device, |
| struct vk_sync *sync, |
| uint32_t handle); |
| |
| VkResult MUST_CHECK vk_sync_export_magma_handle(struct vk_device *device, |
| struct vk_sync *sync, |
| uint32_t *handle_out); |
| #endif |
| |
| VkResult MUST_CHECK vk_sync_move(struct vk_device *device, |
| struct vk_sync *dst, |
| struct vk_sync *src); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* VK_SYNC_H */ |