From 68b8a2f37191f4bf92d6e9d72e7c41aba1b8765e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 1 Apr 2023 19:44:57 +0100 Subject: [PATCH] a/vk: Add command pool helpers --- src/xrt/auxiliary/vk/CMakeLists.txt | 2 + src/xrt/auxiliary/vk/vk_cmd_pool.c | 143 +++++++++++++++++ src/xrt/auxiliary/vk/vk_cmd_pool.h | 228 ++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 src/xrt/auxiliary/vk/vk_cmd_pool.c create mode 100644 src/xrt/auxiliary/vk/vk_cmd_pool.h diff --git a/src/xrt/auxiliary/vk/CMakeLists.txt b/src/xrt/auxiliary/vk/CMakeLists.txt index 3f9df626e..d6108da65 100644 --- a/src/xrt/auxiliary/vk/CMakeLists.txt +++ b/src/xrt/auxiliary/vk/CMakeLists.txt @@ -6,6 +6,8 @@ add_library( vk_bundle_init.c vk_cmd.c vk_cmd.h + vk_cmd_pool.c + vk_cmd_pool.h vk_compositor_flags.c vk_documentation.h vk_function_loaders.c diff --git a/src/xrt/auxiliary/vk/vk_cmd_pool.c b/src/xrt/auxiliary/vk/vk_cmd_pool.c new file mode 100644 index 000000000..77e6afd98 --- /dev/null +++ b/src/xrt/auxiliary/vk/vk_cmd_pool.c @@ -0,0 +1,143 @@ +// Copyright 2019-2023, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Command pool helpers. + * @author Jakob Bornecrantz + * @author Lubosz Sarnecki + * @ingroup aux_vk + */ + +#include "vk/vk_cmd.h" +#include "vk/vk_cmd_pool.h" + + +/* + * + * 'Exported' functions. + * + */ + +XRT_CHECK_RESULT VkResult +vk_cmd_pool_init(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandPoolCreateFlags flags) +{ + VkResult ret; + + XRT_MAYBE_UNUSED int iret = os_mutex_init(&pool->mutex); + assert(iret == 0); + + VkCommandPoolCreateInfo cmd_pool_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = flags, + .queueFamilyIndex = vk->queue_family_index, + }; + + ret = vk->vkCreateCommandPool(vk->device, &cmd_pool_info, NULL, &pool->pool); + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkCreateCommandPool: %s", vk_result_string(ret)); + os_mutex_destroy(&pool->mutex); + } + + return ret; +} + +void +vk_cmd_pool_destroy(struct vk_bundle *vk, struct vk_cmd_pool *pool) +{ + // Early out if never created. + if (pool->pool == VK_NULL_HANDLE) { + return; + } + + vk->vkDestroyCommandPool(vk->device, pool->pool, NULL); + pool->pool = VK_NULL_HANDLE; + + os_mutex_destroy(&pool->mutex); +} + +XRT_CHECK_RESULT VkResult +vk_cmd_pool_create_cmd_buffer_locked(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandBuffer *out_cmd_buffer) +{ + VkCommandBuffer cmd_buffer; + VkResult ret; + + // Allocate the command buffer. + VkCommandBufferAllocateInfo cmd_buffer_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = pool->pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + ret = vk->vkAllocateCommandBuffers(vk->device, &cmd_buffer_info, &cmd_buffer); + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkAllocateCommandBuffers: %s", vk_result_string(ret)); + // Nothing to cleanup + return ret; + } + + *out_cmd_buffer = cmd_buffer; + + return VK_SUCCESS; +} + +XRT_CHECK_RESULT VkResult +vk_cmd_pool_create_and_begin_cmd_buffer_locked(struct vk_bundle *vk, + struct vk_cmd_pool *pool, + VkCommandBufferUsageFlags flags, + VkCommandBuffer *out_cmd_buffer) +{ + VkCommandBuffer cmd_buffer; + VkResult ret; + + ret = vk_cmd_pool_create_cmd_buffer_locked(vk, pool, &cmd_buffer); + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vk_cmd_pool_create_cmd_buffer_locked: %s", vk_result_string(ret)); + // Nothing to cleanup + return ret; + } + + // Start the command buffer as well. + VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = flags, + }; + + ret = vk->vkBeginCommandBuffer(cmd_buffer, &begin_info); + + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkBeginCommandBuffer: %s", vk_result_string(ret)); + goto err_buffer; + } + + *out_cmd_buffer = cmd_buffer; + + return VK_SUCCESS; + + +err_buffer: + vk->vkFreeCommandBuffers(vk->device, pool->pool, 1, &cmd_buffer); + + return ret; +} + +XRT_CHECK_RESULT VkResult +vk_cmd_pool_submit_cmd_buffer_locked(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandBuffer cmd_buffer) +{ + VkResult ret; + + // Do the submit. + VkSubmitInfo submitInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &cmd_buffer, + }; + + ret = vk_cmd_submit_locked(vk, 1, &submitInfo, VK_NULL_HANDLE); + + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vk_cmd_submit_locked: %s", vk_result_string(ret)); + } + + return ret; +} diff --git a/src/xrt/auxiliary/vk/vk_cmd_pool.h b/src/xrt/auxiliary/vk/vk_cmd_pool.h new file mode 100644 index 000000000..ff8507cc0 --- /dev/null +++ b/src/xrt/auxiliary/vk/vk_cmd_pool.h @@ -0,0 +1,228 @@ +// Copyright 2019-2023, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Command pool helpers. + * @author Jakob Bornecrantz + * @author Lubosz Sarnecki + * @ingroup aux_vk + */ + +#pragma once + +#include "vk/vk_helpers.h" +#include "vk/vk_cmd.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * + * Struct(s) + * + */ + +/*! + * Small helper to manage lock around a command pool. + * + * @ingroup aux_vk + */ +struct vk_cmd_pool +{ + VkCommandPool pool; + struct os_mutex mutex; +}; + + +/* + * + * Functions. + * + */ + +/*! + * Create a command buffer pool. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT VkResult +vk_cmd_pool_init(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandPoolCreateFlags flags); + +/*! + * Destroy a command buffer pool, lock must not be held, externally + * synchronizable with all other pool commands. + * + * @public @memberof vk_cmd_pool + */ +void +vk_cmd_pool_destroy(struct vk_bundle *vk, struct vk_cmd_pool *pool); + +/*! + * Create a command buffer, call with the pool mutex held. + * + * @pre Command pool lock must be held, see @ref vk_cmd_pool_lock. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT VkResult +vk_cmd_pool_create_cmd_buffer_locked(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandBuffer *out_cmd_buffer); + +/*! + * Create a command buffer and also begin it, call with the pool mutex held. + * + * @pre Command pool lock must be held. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT VkResult +vk_cmd_pool_create_and_begin_cmd_buffer_locked(struct vk_bundle *vk, + struct vk_cmd_pool *pool, + VkCommandBufferUsageFlags flags, + VkCommandBuffer *out_cmd_buffer); + +/*! + * Submit to the vulkan queue, will take the queue mutex. + * + * @pre Command pool lock must be held, see @ref vk_cmd_pool_lock. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT VkResult +vk_cmd_pool_submit_cmd_buffer_locked(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandBuffer cmd_buffer); + +/*! + * A do everything submit function, will take the queue mutex. Will create a + * fence and wait on the commands to complete. Will also end and destroy the + * passed in command buffer. + * + * @pre Command pool lock must be held, see @ref vk_cmd_pool_lock. + * + * Calls: + * * vkEndCommandBuffer + * * vkCreateFence + * * vkWaitForFences + * * vkDestroyFence + * * vkFreeCommandBuffers + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT static inline VkResult +vk_cmd_pool_end_submit_wait_and_free_cmd_buffer_locked(struct vk_bundle *vk, + struct vk_cmd_pool *pool, + VkCommandBuffer cmd_buffer) +{ + return vk_cmd_end_submit_wait_and_free_cmd_buffer_locked(vk, pool->pool, cmd_buffer); +} + +/*! + * Lock the command pool, needed for creating command buffers, filling out + * commands on any command buffers created from this pool and submitting any + * command buffers created from this pool to a VkQueue. + * + * @public @memberof vk_cmd_pool + */ +static inline void +vk_cmd_pool_lock(struct vk_cmd_pool *pool) +{ + os_mutex_lock(&pool->mutex); +} + +/*! + * Unlock the command pool. + * + * @public @memberof vk_cmd_pool + */ +static inline void +vk_cmd_pool_unlock(struct vk_cmd_pool *pool) +{ + os_mutex_unlock(&pool->mutex); +} + +/*! + * Locks, calls @ref vk_cmd_pool_create_cmd_buffer_locked, and then unlocks the + * command pool. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT static inline VkResult +vk_cmd_pool_create_cmd_buffer(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandBuffer *out_cmd_buffer) +{ + vk_cmd_pool_lock(pool); + VkResult ret = vk_cmd_pool_create_cmd_buffer_locked(vk, pool, out_cmd_buffer); + vk_cmd_pool_unlock(pool); + return ret; +} + +/*! + * Locks, calls @ref vk_cmd_pool_create_and_begin_cmd_buffer_locked, and then + * unlocks the command pool. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT static inline VkResult +vk_cmd_pool_create_and_begin_cmd_buffer(struct vk_bundle *vk, + struct vk_cmd_pool *pool, + VkCommandBufferUsageFlags flags, + VkCommandBuffer *out_cmd_buffer) +{ + vk_cmd_pool_lock(pool); + VkResult ret = vk_cmd_pool_create_and_begin_cmd_buffer_locked(vk, pool, flags, out_cmd_buffer); + vk_cmd_pool_unlock(pool); + return ret; +} + +/*! + * Locks, calls @ref vk_cmd_pool_submit_locked, and then unlocks the command + * pool. Will during the call take the queue lock and release it. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT static inline VkResult +vk_cmd_pool_submit( + struct vk_bundle *vk, struct vk_cmd_pool *pool, uint32_t count, const VkSubmitInfo *infos, VkFence fence) +{ + vk_cmd_pool_lock(pool); + VkResult ret = vk_cmd_submit_locked(vk, count, infos, fence); + vk_cmd_pool_unlock(pool); + return ret; +} + +/*! + * Locks, calls @ref vk_cmd_pool_submit_cmd_buffer_locked, and then unlocks the + * command pool. Will during the call take the queue lock and release it. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT static inline VkResult +vk_cmd_pool_submit_cmd_buffer(struct vk_bundle *vk, struct vk_cmd_pool *pool, VkCommandBuffer cmd_buffer) +{ + vk_cmd_pool_lock(pool); + VkResult ret = vk_cmd_pool_submit_cmd_buffer_locked(vk, pool, cmd_buffer); + vk_cmd_pool_unlock(pool); + return ret; +} + +/*! + * Locks, calls @ref vk_cmd_pool_end_submit_wait_and_free_cmd_buffer_locked, and + * then unlocks the command pool. Will during the call take the queue lock and + * release it. + * + * @public @memberof vk_cmd_pool + */ +XRT_CHECK_RESULT static inline VkResult +vk_cmd_pool_end_submit_wait_and_free_cmd_buffer(struct vk_bundle *vk, + struct vk_cmd_pool *pool, + VkCommandBuffer cmd_buffer) +{ + vk_cmd_pool_lock(pool); + VkResult ret = vk_cmd_pool_end_submit_wait_and_free_cmd_buffer_locked(vk, pool, cmd_buffer); + vk_cmd_pool_unlock(pool); + return ret; +} + + +#ifdef __cplusplus +} +#endif