From 885497a4456256a147d9e7e30daa3170e461d7d6 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Thu, 28 Sep 2017 22:33:31 +0200 Subject: vo_gpu: vulkan: reorganize vk_cmd slightly Instead of associating a single VkSemaphore with every command buffer and allowing the user to ad-hoc wait on it during submission, make the raw semaphores-to-signal array work like the raw semaphores-to-wait-on array. Doesn't really provide a clear benefit yet, but it's required for upcoming modifications. --- video/out/vulkan/context.c | 45 +++++++++++++++++++++++++-------------------- video/out/vulkan/ra_vk.c | 15 +++++++-------- video/out/vulkan/ra_vk.h | 7 +++---- video/out/vulkan/utils.c | 28 +++++++++++----------------- video/out/vulkan/utils.h | 20 ++++++++++++-------- 5 files changed, 58 insertions(+), 57 deletions(-) (limited to 'video') diff --git a/video/out/vulkan/context.c b/video/out/vulkan/context.c index 5d9b40cbb5..b51bb78578 100644 --- a/video/out/vulkan/context.c +++ b/video/out/vulkan/context.c @@ -121,9 +121,10 @@ struct priv { // state of the images: struct ra_tex **images; // ra_tex wrappers for the vkimages int num_images; // size of images - VkSemaphore *acquired; // pool of semaphores used to synchronize images - int num_acquired; // size of this pool - int idx_acquired; // index of next free semaphore within this pool + VkSemaphore *sems_in; // pool of semaphores used to synchronize images + VkSemaphore *sems_out; // outgoing semaphores (rendering complete) + int num_sems; + int idx_sems; // index of next free semaphore pair int last_imgidx; // the image index last acquired (for submit) }; @@ -248,13 +249,12 @@ void ra_vk_ctx_uninit(struct ra_ctx *ctx) for (int i = 0; i < p->num_images; i++) ra_tex_free(ctx->ra, &p->images[i]); - for (int i = 0; i < p->num_acquired; i++) - vkDestroySemaphore(vk->dev, p->acquired[i], MPVK_ALLOCATOR); + for (int i = 0; i < p->num_sems; i++) { + vkDestroySemaphore(vk->dev, p->sems_in[i], MPVK_ALLOCATOR); + vkDestroySemaphore(vk->dev, p->sems_out[i], MPVK_ALLOCATOR); + } vkDestroySwapchainKHR(vk->dev, p->swapchain, MPVK_ALLOCATOR); - - talloc_free(p->images); - talloc_free(p->acquired); ctx->ra->fns->destroy(ctx->ra); ctx->ra = NULL; } @@ -382,13 +382,19 @@ bool ra_vk_ctx_resize(struct ra_swapchain *sw, int w, int h) VK(vkGetSwapchainImagesKHR(vk->dev, p->swapchain, &num, vkimages)); // If needed, allocate some more semaphores - while (num > p->num_acquired) { - VkSemaphore sem; + while (num > p->num_sems) { + VkSemaphore sem_in, sem_out; static const VkSemaphoreCreateInfo seminfo = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, }; - VK(vkCreateSemaphore(vk->dev, &seminfo, MPVK_ALLOCATOR, &sem)); - MP_TARRAY_APPEND(NULL, p->acquired, p->num_acquired, sem); + VK(vkCreateSemaphore(vk->dev, &seminfo, MPVK_ALLOCATOR, &sem_in)); + VK(vkCreateSemaphore(vk->dev, &seminfo, MPVK_ALLOCATOR, &sem_out)); + + int idx = p->num_sems++; + MP_TARRAY_GROW(p, p->sems_in, idx); + MP_TARRAY_GROW(p, p->sems_out, idx); + p->sems_in[idx] = sem_in; + p->sems_out[idx] = sem_out; } // Recreate the ra_tex wrappers @@ -396,7 +402,7 @@ bool ra_vk_ctx_resize(struct ra_swapchain *sw, int w, int h) ra_tex_free(ra, &p->images[i]); p->num_images = num; - MP_TARRAY_GROW(NULL, p->images, p->num_images); + MP_TARRAY_GROW(p, p->images, p->num_images); for (int i = 0; i < num; i++) { p->images[i] = ra_vk_wrap_swapchain_img(ra, vkimages[i], sinfo); if (!p->images[i]) @@ -444,7 +450,7 @@ static bool start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo) uint32_t imgidx = 0; MP_TRACE(vk, "vkAcquireNextImageKHR\n"); VkResult res = vkAcquireNextImageKHR(vk->dev, p->swapchain, UINT64_MAX, - p->acquired[p->idx_acquired], NULL, + p->sems_in[p->idx_sems], NULL, &imgidx); if (res == VK_ERROR_OUT_OF_DATE_KHR) goto error; // just return in this case @@ -469,12 +475,11 @@ static bool submit_frame(struct ra_swapchain *sw, const struct vo_frame *frame) if (!p->swapchain) goto error; - VkSemaphore acquired = p->acquired[p->idx_acquired++]; - p->idx_acquired %= p->num_acquired; + int semidx = p->idx_sems++; + p->idx_sems %= p->num_sems; - VkSemaphore done; - if (!ra_vk_submit(ra, p->images[p->last_imgidx], acquired, &done, - &p->frames_in_flight)) + if (!ra_vk_submit(ra, p->images[p->last_imgidx], p->sems_in[semidx], + p->sems_out[semidx], &p->frames_in_flight)) goto error; // Older nvidia drivers can spontaneously combust when submitting to the @@ -488,7 +493,7 @@ static bool submit_frame(struct ra_swapchain *sw, const struct vo_frame *frame) VkPresentInfoKHR pinfo = { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .waitSemaphoreCount = 1, - .pWaitSemaphores = &done, + .pWaitSemaphores = &p->sems_out[semidx], .swapchainCount = 1, .pSwapchains = &p->swapchain, .pImageIndices = &p->last_imgidx, diff --git a/video/out/vulkan/ra_vk.c b/video/out/vulkan/ra_vk.c index 9101233495..e0e13391af 100644 --- a/video/out/vulkan/ra_vk.c +++ b/video/out/vulkan/ra_vk.c @@ -34,16 +34,13 @@ static struct vk_cmd *vk_require_cmd(struct ra *ra) return p->cmd; } -// Note: This technically follows the flush() API, but we don't need -// to expose that (and in fact, it's a bad idea) since we control flushing -// behavior with ra_vk_present_frame already. -static bool vk_flush(struct ra *ra, VkSemaphore *done) +static bool vk_flush(struct ra *ra) { struct ra_vk *p = ra->priv; struct mpvk_ctx *vk = ra_vk_get(ra); if (p->cmd) { - if (!vk_cmd_submit(vk, p->cmd, done)) + if (!vk_cmd_submit(vk, p->cmd)) return false; p->cmd = NULL; } @@ -74,7 +71,7 @@ static void vk_destroy_ra(struct ra *ra) struct ra_vk *p = ra->priv; struct mpvk_ctx *vk = ra_vk_get(ra); - vk_flush(ra, NULL); + vk_flush(ra); mpvk_dev_wait_cmds(vk, UINT64_MAX); ra_tex_free(ra, &p->clear_tex); @@ -1715,7 +1712,7 @@ static void present_cb(void *priv, int *inflight) } bool ra_vk_submit(struct ra *ra, struct ra_tex *tex, VkSemaphore acquired, - VkSemaphore *done, int *inflight) + VkSemaphore done, int *inflight) { struct vk_cmd *cmd = vk_require_cmd(ra); if (!cmd) @@ -1740,7 +1737,9 @@ bool ra_vk_submit(struct ra *ra, struct ra_tex *tex, VkSemaphore acquired, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT); - return vk_flush(ra, done); + vk_cmd_sig(cmd, done); + + return vk_flush(ra); error: return false; diff --git a/video/out/vulkan/ra_vk.h b/video/out/vulkan/ra_vk.h index 893421bc59..d15b6380f0 100644 --- a/video/out/vulkan/ra_vk.h +++ b/video/out/vulkan/ra_vk.h @@ -18,13 +18,12 @@ struct ra_tex *ra_vk_wrap_swapchain_img(struct ra *ra, VkImage vkimg, // This function flushes the command buffers, transitions `tex` (which must be // a wrapped swapchain image) into a format suitable for presentation, and -// submits the current rendering commands. The indicated semaphore must fire -// before the submitted command can run. If `done` is non-NULL, it will be -// set to a semaphore that fires once the command completes. If `inflight` +// submits the current rendering commands. `acquired` must fire before the +// command can run, and `done` will fire after it completes. If `inflight` // is non-NULL, it will be incremented when the command starts and decremented // when it completes. bool ra_vk_submit(struct ra *ra, struct ra_tex *tex, VkSemaphore acquired, - VkSemaphore *done, int *inflight); + VkSemaphore done, int *inflight); // May be called on a struct ra of any type. Returns NULL if the ra is not // a vulkan ra. diff --git a/video/out/vulkan/utils.c b/video/out/vulkan/utils.c index ba7ff66f2b..7c8511a9d2 100644 --- a/video/out/vulkan/utils.c +++ b/video/out/vulkan/utils.c @@ -484,6 +484,7 @@ static void vk_cmd_reset(struct mpvk_ctx *vk, struct vk_cmd *cmd) cmd->num_callbacks = 0; cmd->num_deps = 0; + cmd->num_sigs = 0; // also make sure to reset vk->last_cmd in case this was the last command if (vk->last_cmd == cmd) @@ -497,7 +498,6 @@ static void vk_cmd_destroy(struct mpvk_ctx *vk, struct vk_cmd *cmd) vk_cmd_poll(vk, cmd, UINT64_MAX); vk_cmd_reset(vk, cmd); - vkDestroySemaphore(vk->dev, cmd->done, MPVK_ALLOCATOR); vkDestroyFence(vk->dev, cmd->fence, MPVK_ALLOCATOR); vkFreeCommandBuffers(vk->dev, cmd->pool->pool, 1, &cmd->buf); @@ -525,12 +525,6 @@ static struct vk_cmd *vk_cmd_create(struct mpvk_ctx *vk, struct vk_cmdpool *pool VK(vkCreateFence(vk->dev, &finfo, MPVK_ALLOCATOR, &cmd->fence)); - VkSemaphoreCreateInfo sinfo = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - }; - - VK(vkCreateSemaphore(vk->dev, &sinfo, MPVK_ALLOCATOR, &cmd->done)); - return cmd; error: @@ -547,14 +541,18 @@ 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) +void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, VkPipelineStageFlags stage) { int idx = cmd->num_deps++; MP_TARRAY_GROW(cmd, cmd->deps, idx); MP_TARRAY_GROW(cmd, cmd->depstages, idx); cmd->deps[idx] = dep; - cmd->depstages[idx] = depstage; + cmd->depstages[idx] = stage; +} + +void vk_cmd_sig(struct vk_cmd *cmd, VkSemaphore sig) +{ + MP_TARRAY_APPEND(cmd, cmd->sigs, cmd->num_sigs, sig); } static void vk_cmdpool_destroy(struct mpvk_ctx *vk, struct vk_cmdpool *pool) @@ -667,7 +665,7 @@ error: return NULL; } -bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd, VkSemaphore *done) +bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd) { struct vk_cmdpool *pool = cmd->pool; @@ -680,14 +678,10 @@ bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd, VkSemaphore *done) .waitSemaphoreCount = cmd->num_deps, .pWaitSemaphores = cmd->deps, .pWaitDstStageMask = cmd->depstages, + .signalSemaphoreCount = cmd->num_sigs, + .pSignalSemaphores = cmd->sigs, }; - if (done) { - sinfo.signalSemaphoreCount = 1; - sinfo.pSignalSemaphores = &cmd->done; - *done = cmd->done; - } - VK(vkResetFences(vk->dev, 1, &cmd->fence)); VK(vkQueueSubmit(cmd->queue, 1, &sinfo, cmd->fence)); MP_TRACE(vk, "Submitted command on queue %p (QF %d)\n", (void *)cmd->queue, diff --git a/video/out/vulkan/utils.h b/video/out/vulkan/utils.h index 36a0e3c5d0..3ade92d6a0 100644 --- a/video/out/vulkan/utils.h +++ b/video/out/vulkan/utils.h @@ -93,12 +93,15 @@ struct vk_cmd { 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; VkPipelineStageFlags *depstages; int num_deps; + // The signals represent semaphores that fire once the command finishes + // executing. These are also not owned by the vk_cmd + VkSemaphore *sigs; + int num_sigs; // Since VkFences are useless, we have to manually track "callbacks" // to fire once the VkFence completes. These are used for multiple purposes, // ranging from garbage collection (resource deallocation) to fencing. @@ -110,10 +113,13 @@ struct vk_cmd { // bool will be set to `true` once the command completes, or shortly thereafter. void vk_cmd_callback(struct vk_cmd *cmd, vk_cb callback, void *p, void *arg); -// Associate a dependency for the current command. This semaphore must signal -// by the corresponding stage before the command may execute. -void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, - VkPipelineStageFlags depstage); +// Associate a raw dependency for the current command. This semaphore must +// signal by the corresponding stage before the command may execute. +void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, VkPipelineStageFlags stage); + +// Associate a raw signal with the current command. This semaphore will signal +// after the command completes. +void vk_cmd_sig(struct vk_cmd *cmd, VkSemaphore sig); // Command pool / queue family hybrid abstraction struct vk_cmdpool { @@ -136,10 +142,8 @@ struct vk_cmd *vk_cmd_begin(struct mpvk_ctx *vk, struct vk_cmdpool *pool); // 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. // Returns whether successful. -bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd, VkSemaphore *done); +bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd); // Rotate the queues for each vk_cmdpool. Call this once per frame to ensure // good parallelism between frames when using multiple queues -- cgit v1.2.3