diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index e46868d9b..5583bb660 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -67,6 +67,8 @@ if(XRT_HAVE_VULKAN) comp_util STATIC util/comp_base.h util/comp_base.c + util/comp_semaphore.h + util/comp_semaphore.c util/comp_swapchain.h util/comp_swapchain.c util/comp_sync.h diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 5daf16b9e..cd0a71184 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -39,6 +39,8 @@ compositor_srcs = [ 'render/comp_util.c', 'util/comp_base.h', 'util/comp_base.c', + 'util/comp_semaphore.h', + 'util/comp_semaphore.c', 'util/comp_swapchain.h', 'util/comp_swapchain.c', 'util/comp_sync.h', diff --git a/src/xrt/compositor/util/comp_base.c b/src/xrt/compositor/util/comp_base.c index 5bdc54032..4620ba79d 100644 --- a/src/xrt/compositor/util/comp_base.c +++ b/src/xrt/compositor/util/comp_base.c @@ -1,4 +1,4 @@ -// Copyright 2019-2021, Collabora, Ltd. +// Copyright 2019-2022, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -11,6 +11,7 @@ #include "util/u_trace_marker.h" #include "util/comp_base.h" +#include "util/comp_semaphore.h" /* @@ -76,6 +77,16 @@ base_import_fence(struct xrt_compositor *xc, xrt_graphics_sync_handle_t handle, return comp_fence_import(&cb->vk, handle, out_xcf); } +static xrt_result_t +base_create_semaphore(struct xrt_compositor *xc, + xrt_graphics_sync_handle_t *out_handle, + struct xrt_compositor_semaphore **out_xcsem) +{ + struct comp_base *cb = comp_base(xc); + + return comp_semaphore_create(&cb->vk, out_handle, out_xcsem); +} + static xrt_result_t base_layer_begin(struct xrt_compositor *xc, int64_t frame_id, @@ -234,6 +245,7 @@ comp_base_init(struct comp_base *cb) { cb->base.base.create_swapchain = base_create_swapchain; cb->base.base.import_swapchain = base_import_swapchain; + cb->base.base.create_semaphore = base_create_semaphore; cb->base.base.import_fence = base_import_fence; cb->base.base.layer_begin = base_layer_begin; cb->base.base.layer_stereo_projection = base_layer_stereo_projection; diff --git a/src/xrt/compositor/util/comp_semaphore.c b/src/xrt/compositor/util/comp_semaphore.c new file mode 100644 index 000000000..32fca0fc5 --- /dev/null +++ b/src/xrt/compositor/util/comp_semaphore.c @@ -0,0 +1,172 @@ +// Copyright 2019-2022, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Independent semaphore implementation. + * @author Jakob Bornecrantz + * @ingroup comp_util + */ + +#include "util/comp_semaphore.h" + + +/* + * + * Member functions. + * + */ + +#ifdef VK_KHR_timeline_semaphore +static xrt_result_t +semaphore_wait(struct xrt_compositor_semaphore *xcsem, uint64_t value, uint64_t timeout_ns) +{ + struct comp_semaphore *csem = comp_semaphore(xcsem); + struct vk_bundle *vk = csem->vk; + VkResult ret; + + VkSemaphoreWaitInfo wait_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .flags = 0, + .semaphoreCount = 1, + .pSemaphores = &csem->semaphore, + .pValues = &value, + }; + + ret = vk->vkWaitSemaphores( // + vk->device, // device + &wait_info, // pWaitInfo + timeout_ns); // timeout + if (ret == VK_TIMEOUT) { + return XRT_TIMEOUT; + } + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkWaitSemaphores: %s", vk_result_string(ret)); + return XRT_ERROR_VULKAN; + } + + return XRT_SUCCESS; +} + +static void +semaphore_destroy(struct xrt_compositor_semaphore *xcsem) +{ + struct comp_semaphore *csem = comp_semaphore(xcsem); + struct vk_bundle *vk = csem->vk; + + vk->vkDestroySemaphore( // + vk->device, // device + csem->semaphore, // semaphore + NULL); // pAllocator + + free(csem); +} +#endif + + +/* + * + * 'Exported' functions. + * + */ + +xrt_result_t +comp_semaphore_create(struct vk_bundle *vk, + xrt_graphics_sync_handle_t *out_handle, + struct xrt_compositor_semaphore **out_xcsem) +{ +#ifdef VK_KHR_timeline_semaphore + VkResult ret; + + if (!vk->features.timeline_semaphore) { + return XRT_ERROR_VULKAN; + } + + VkExternalSemaphoreHandleTypeFlags handle_type = 0; + + +#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) + if (!vk->external.timeline_semaphore_opaque_fd) { + VK_ERROR(vk, "External timeline semaphore opaque fd not supported!"); + return XRT_ERROR_VULKAN; + } else { + handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + } +#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) + if (!vk->external.timeline_semaphore_win32_handle) { + VK_ERROR(vk, "External timeline semaphore win32 handle not supported!"); + return XRT_ERROR_VULKAN; + } else { + handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; + } +#else +#error "Need to port semaphore creation code." +#endif + + + VkExportSemaphoreCreateInfo export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, + .handleTypes = handle_type, + }; + + VkSemaphoreTypeCreateInfo type_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .pNext = &export_info, + .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, + .initialValue = 0, + }; + + VkSemaphoreCreateInfo semaphore_create_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &type_info, + .flags = 0, + }; + + VkSemaphore semaphore = VK_NULL_HANDLE; + ret = vk->vkCreateSemaphore( // + vk->device, // dev + &semaphore_create_info, // pCreateInfo + NULL, // pAllocator + &semaphore); // pSemaphore + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkCreateSemaphore: %s", vk_result_string(ret)); + return XRT_ERROR_VULKAN; + } + + +#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) + VkSemaphoreGetFdInfoKHR get_fd_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, + .semaphore = semaphore, + .handleType = handle_type, + }; + + ret = vk->vkGetSemaphoreFdKHR(vk->device, &get_fd_info, out_handle); + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkGetSemaphoreFdKHR: %s", vk_result_string(ret)); + vk->vkDestroySemaphore(vk->device, semaphore, NULL); + return XRT_ERROR_VULKAN; + } +#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) +#error "No windows port" +#else +#error "Need to port semaphore creation code." +#endif + + + struct comp_semaphore *csem = U_TYPED_CALLOC(struct comp_semaphore); + + csem->base.reference.count = 1; + csem->base.destroy = semaphore_destroy; + csem->base.wait = semaphore_wait; + csem->semaphore = semaphore; + csem->vk = vk; + + *out_xcsem = &csem->base; + + return XRT_SUCCESS; +#else + // How did you even get here? + VK_ERROR(vk, "No compile time support for VK_KHR_timeline_semaphore!"); + return XRT_ERROR_VULKAN; +#endif +} diff --git a/src/xrt/compositor/util/comp_semaphore.h b/src/xrt/compositor/util/comp_semaphore.h new file mode 100644 index 000000000..ea303f3f2 --- /dev/null +++ b/src/xrt/compositor/util/comp_semaphore.h @@ -0,0 +1,76 @@ +// Copyright 2019-2022, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Independent semaphore implementation. + * @author Jakob Bornecrantz + * @ingroup comp_util + */ + +#pragma once + +#include "xrt/xrt_compositor.h" +#include "vk/vk_helpers.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * A simple implementation of the xrt_compositor_semaphore interface. + * + * @ingroup comp_util + * @implements xrt_compositor_swapchain + * @see comp_compositor + */ +struct comp_semaphore +{ + struct xrt_compositor_semaphore base; + + struct vk_bundle *vk; + + VkSemaphore semaphore; +}; + + +/* + * + * Helper functions. + * + */ + +/*! + * Convenience function to convert a xrt_compositor_semaphore to a comp_semaphore. + * + * @ingroup comp_util + * @private @memberof comp_semaphore + */ +static inline struct comp_semaphore * +comp_semaphore(struct xrt_compositor_semaphore *xcsem) +{ + return (struct comp_semaphore *)xcsem; +} + + +/* + * + * 'Exported' functions. + * + */ + +/*! + * Creates a @ref comp_semaphore, used to implement compositor functionality. + * + * @ingroup comp_util + */ +xrt_result_t +comp_semaphore_create(struct vk_bundle *vk, + xrt_graphics_sync_handle_t *out_handle, + struct xrt_compositor_semaphore **out_xcsem); + + +#ifdef __cplusplus +} +#endif