From 4e34615872011f906bf653f61e7ac75d2066a06b Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Wed, 27 Sep 2017 17:08:06 +0200 Subject: vo_gpu: vulkan: refactor vk_cmdpool 1. No more static arrays (deps / callbacks / queues / cmds) 2. Allows safely recording multiple commands at the same time 3. Uses resources optimally by never over-allocating commands --- video/out/vulkan/utils.h | 56 ++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) (limited to 'video/out/vulkan/utils.h') diff --git a/video/out/vulkan/utils.h b/video/out/vulkan/utils.h index 0cc8a29430..36a0e3c5d0 100644 --- a/video/out/vulkan/utils.h +++ b/video/out/vulkan/utils.h @@ -60,17 +60,15 @@ struct mpvk_device_opts { // Create a logical device and initialize the vk_cmdpools bool mpvk_device_init(struct mpvk_ctx *vk, struct mpvk_device_opts opts); -// Wait until all commands submitted to all queues have completed -void mpvk_pool_wait_idle(struct mpvk_ctx *vk, struct vk_cmdpool *pool); -void mpvk_dev_wait_idle(struct mpvk_ctx *vk); - -// Wait until at least one command submitted to any queue has completed, and -// process the callbacks. Good for event loops that need to delay until a -// command completes. Will block at most `timeout` nanoseconds. If used with -// 0, it only garbage collects completed commands without blocking. -void mpvk_pool_poll_cmds(struct mpvk_ctx *vk, struct vk_cmdpool *pool, +// Wait for all currently pending commands to have completed. This is the only +// function that actually processes the callbacks. Will wait at most `timeout` +// nanoseconds for the completion of each command. Using it with a value of +// UINT64_MAX effectively means waiting until the pool/device is idle. The +// timeout may also be passed as 0, in which case this function will not block, +// but only poll for completed commands. +void mpvk_pool_wait_cmds(struct mpvk_ctx *vk, struct vk_cmdpool *pool, uint64_t timeout); -void mpvk_dev_poll_cmds(struct mpvk_ctx *vk, uint32_t timeout); +void mpvk_dev_wait_cmds(struct mpvk_ctx *vk, uint64_t timeout); // Since lots of vulkan operations need to be done lazily once the affected // resources are no longer in use, provide an abstraction for tracking these. @@ -88,19 +86,18 @@ struct vk_callback { // This will essentially run once the device is completely idle. void vk_dev_callback(struct mpvk_ctx *vk, vk_cb callback, void *p, void *arg); -#define MPVK_MAX_CMD_DEPS 8 - // Helper wrapper around command buffers that also track dependencies, // callbacks and synchronization primitives struct vk_cmd { struct vk_cmdpool *pool; // pool it was allocated from - VkCommandBuffer buf; - VkFence fence; // the fence guards cmd buffer reuse - VkSemaphore done; // the semaphore signals when execution is done + VkQueue queue; // the submission queue (for recording/pending) + VkCommandBuffer buf; // the command buffer itself + VkFence fence; // the fence guards cmd buffer reuse + VkSemaphore done; // the semaphore signals when execution is done // The semaphores represent dependencies that need to complete before // this command can be executed. These are *not* owned by the vk_cmd - VkSemaphore deps[MPVK_MAX_CMD_DEPS]; - VkPipelineStageFlags depstages[MPVK_MAX_CMD_DEPS]; + VkSemaphore *deps; + VkPipelineStageFlags *depstages; int num_deps; // Since VkFences are useless, we have to manually track "callbacks" // to fire once the VkFence completes. These are used for multiple purposes, @@ -118,30 +115,29 @@ void vk_cmd_callback(struct vk_cmd *cmd, vk_cb callback, void *p, void *arg); void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, VkPipelineStageFlags depstage); -#define MPVK_MAX_QUEUES 8 -#define MPVK_MAX_CMDS 64 - // Command pool / queue family hybrid abstraction struct vk_cmdpool { VkQueueFamilyProperties props; - uint32_t qf; // queue family index + int qf; // queue family index VkCommandPool pool; - VkQueue queues[MPVK_MAX_QUEUES]; - int qcount; - int qindex; + VkQueue *queues; + int num_queues; + int idx_queues; // Command buffers associated with this queue - struct vk_cmd cmds[MPVK_MAX_CMDS]; - int cindex; - int cindex_pending; + struct vk_cmd **cmds_available; // available for re-recording + struct vk_cmd **cmds_pending; // submitted but not completed + int num_cmds_available; + int num_cmds_pending; }; -// Fetch the next command buffer from a command pool and begin recording to it. +// Fetch a command buffer from a command pool and begin recording to it. // Returns NULL on failure. struct vk_cmd *vk_cmd_begin(struct mpvk_ctx *vk, struct vk_cmdpool *pool); -// Finish the currently recording command buffer and submit it for execution. +// Finish recording a command buffer and submit it for execution. This function +// takes over ownership of *cmd, i.e. the caller should not touch it again. // If `done` is not NULL, it will be set to a semaphore that will signal once -// the command completes. (And MUST have a corresponding semaphore wait) +// the command completes. // Returns whether successful. bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd, VkSemaphore *done); -- cgit v1.2.3