From c5ac1d16692ea95676f28f41dbc0e4e01d96959b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 2 Nov 2021 10:20:00 -0500 Subject: [PATCH] vulkan: Add an emulated binary vk_sync type This wraps a timeline vk_sync type and turns it into a binary one. This is useful for, for instance, driver layered on D3D12. Reviewed-by: Lionel Landwerlin Acked-by: Bas Nieuwenhuizen Part-of: --- src/vulkan/runtime/meson.build | 2 + src/vulkan/runtime/vk_queue.c | 15 ++++ src/vulkan/runtime/vk_sync_binary.c | 138 ++++++++++++++++++++++++++++++++++++ src/vulkan/runtime/vk_sync_binary.h | 79 +++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 src/vulkan/runtime/vk_sync_binary.c create mode 100644 src/vulkan/runtime/vk_sync_binary.h diff --git a/src/vulkan/runtime/meson.build b/src/vulkan/runtime/meson.build index dfc3765..a49506c 100644 --- a/src/vulkan/runtime/meson.build +++ b/src/vulkan/runtime/meson.build @@ -58,6 +58,8 @@ vulkan_runtime_files = files( 'vk_shader_module.h', 'vk_sync.c', 'vk_sync.h', + 'vk_sync_binary.c', + 'vk_sync_binary.h', 'vk_sync_timeline.c', 'vk_sync_timeline.h', 'vk_synchronization2.c', diff --git a/src/vulkan/runtime/vk_queue.c b/src/vulkan/runtime/vk_queue.c index 6a2e44c..6227383 100644 --- a/src/vulkan/runtime/vk_queue.c +++ b/src/vulkan/runtime/vk_queue.c @@ -35,6 +35,7 @@ #include "vk_physical_device.h" #include "vk_semaphore.h" #include "vk_sync.h" +#include "vk_sync_binary.h" #include "vk_sync_timeline.h" #include "vk_util.h" @@ -281,6 +282,13 @@ vk_queue_submit_final(struct vk_queue *queue, submit->waits[i].wait_value = 0; } + struct vk_sync_binary *binary = + vk_sync_as_binary(submit->waits[i].sync); + if (binary) { + submit->waits[i].sync = &binary->timeline; + submit->waits[i].wait_value = binary->next_point; + } + assert((submit->waits[i].sync->flags & VK_SYNC_IS_TIMELINE) || submit->waits[i].wait_value == 0); @@ -300,6 +308,13 @@ vk_queue_submit_final(struct vk_queue *queue, for (uint32_t i = 0; i < submit->signal_count; i++) { assert((submit->signals[i].sync->flags & VK_SYNC_IS_TIMELINE) || submit->signals[i].signal_value == 0); + + struct vk_sync_binary *binary = + vk_sync_as_binary(submit->signals[i].sync); + if (binary) { + submit->signals[i].sync = &binary->timeline; + submit->signals[i].signal_value = ++binary->next_point; + } } result = queue->driver_submit(queue, submit); diff --git a/src/vulkan/runtime/vk_sync_binary.c b/src/vulkan/runtime/vk_sync_binary.c new file mode 100644 index 0000000..3d2720f --- /dev/null +++ b/src/vulkan/runtime/vk_sync_binary.c @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#include "vk_sync_binary.h" + +#include "vk_util.h" + +static struct vk_sync_binary * +to_vk_sync_binary(struct vk_sync *sync) +{ + assert(sync->type->init == vk_sync_binary_init); + + return container_of(sync, struct vk_sync_binary, sync); +} + +VkResult +vk_sync_binary_init(struct vk_device *device, + struct vk_sync *sync, + uint64_t initial_value) +{ + struct vk_sync_binary *binary = to_vk_sync_binary(sync); + + const struct vk_sync_binary_type *btype = + container_of(binary->sync.type, struct vk_sync_binary_type, sync); + + assert(!(sync->flags & VK_SYNC_IS_TIMELINE)); + assert(!(sync->flags & VK_SYNC_IS_SHAREABLE)); + + binary->next_point = (initial_value == 0); + + return vk_sync_init(device, &binary->timeline, btype->timeline_type, + VK_SYNC_IS_TIMELINE, 0 /* initial_value */); +} + +static void +vk_sync_binary_finish(struct vk_device *device, + struct vk_sync *sync) +{ + struct vk_sync_binary *binary = to_vk_sync_binary(sync); + + vk_sync_finish(device, &binary->timeline); +} + +static VkResult +vk_sync_binary_reset(struct vk_device *device, + struct vk_sync *sync) +{ + struct vk_sync_binary *binary = to_vk_sync_binary(sync); + + binary->next_point++; + + return VK_SUCCESS; +} + +static VkResult +vk_sync_binary_signal(struct vk_device *device, + struct vk_sync *sync, + uint64_t value) +{ + struct vk_sync_binary *binary = to_vk_sync_binary(sync); + + assert(value == 0); + + return vk_sync_signal(device, &binary->timeline, binary->next_point); +} + +static VkResult +vk_sync_binary_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) +{ + STACK_ARRAY(struct vk_sync_wait, timeline_waits, wait_count); + + for (uint32_t i = 0; i < wait_count; i++) { + struct vk_sync_binary *binary = to_vk_sync_binary(waits[i].sync); + + timeline_waits[i] = (struct vk_sync_wait) { + .sync = &binary->timeline, + .stage_mask = waits[i].stage_mask, + .wait_value = binary->next_point, + }; + } + + VkResult result = vk_sync_wait_many(device, wait_count, timeline_waits, + wait_flags, abs_timeout_ns); + + STACK_ARRAY_FINISH(timeline_waits); + + return result; +} + +struct vk_sync_binary_type +vk_sync_binary_get_type(const struct vk_sync_type *timeline_type) +{ + assert(timeline_type->features & VK_SYNC_FEATURE_TIMELINE); + + return (struct vk_sync_binary_type) { + .sync = { + .size = offsetof(struct vk_sync_binary, timeline) + + timeline_type->size, + .features = VK_SYNC_FEATURE_BINARY | + VK_SYNC_FEATURE_GPU_WAIT | + VK_SYNC_FEATURE_CPU_WAIT | + VK_SYNC_FEATURE_CPU_RESET | + VK_SYNC_FEATURE_CPU_SIGNAL | + VK_SYNC_FEATURE_WAIT_ANY | + VK_SYNC_FEATURE_WAIT_PENDING, + .init = vk_sync_binary_init, + .finish = vk_sync_binary_finish, + .reset = vk_sync_binary_reset, + .signal = vk_sync_binary_signal, + .wait_many = vk_sync_binary_wait_many, + }, + .timeline_type = timeline_type, + }; +} diff --git a/src/vulkan/runtime/vk_sync_binary.h b/src/vulkan/runtime/vk_sync_binary.h new file mode 100644 index 0000000..8a4ceeb --- /dev/null +++ b/src/vulkan/runtime/vk_sync_binary.h @@ -0,0 +1,79 @@ +/* + * 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_BINARY_H +#define VK_SYNC_BINARY_H + +#include "vk_sync.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_sync_binary_type { + struct vk_sync_type sync; + const struct vk_sync_type *timeline_type; +}; + +struct vk_sync_binary_type +vk_sync_binary_get_type(const struct vk_sync_type *timeline_type); + +/** Implements a binary vk_sync type on top of a timeline vk_sync + * + * This is useful when targeting Windows APIs such as D3D12 which only have + * timelines and have no concept of a binary synchronization object. Because + * binary vk_sync emulation requires tracking additional state (the next time + * point), fences and semaphores created from this type cannot support any of + * the sharing APIs. + */ +struct vk_sync_binary { + struct vk_sync sync; + + uint64_t next_point; + + struct vk_sync timeline; +}; + +VkResult vk_sync_binary_init(struct vk_device *device, + struct vk_sync *sync, + uint64_t initial_value); + +static inline bool +vk_sync_type_is_vk_sync_binary(const struct vk_sync_type *type) +{ + return type->init == vk_sync_binary_init; +} + +static inline struct vk_sync_binary * +vk_sync_as_binary(struct vk_sync *sync) +{ + if (!vk_sync_type_is_vk_sync_binary(sync->type)) + return NULL; + + return container_of(sync, struct vk_sync_binary, sync); +} + +#ifdef __cplusplus +} +#endif + +#endif /* VK_TIMELINE_H */ -- 2.7.4