From 109e373e0c5c5f5b98a1c5769b124c301979ca10 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 28 Sep 2022 21:34:06 +0000 Subject: [PATCH] c/main: Move ownership of present/render semaphores to comp_target Co-authored-by: Jakob Bornecrantz --- src/xrt/compositor/main/comp_renderer.c | 134 ++++++++++-------- src/xrt/compositor/main/comp_target.h | 45 ++++-- .../compositor/main/comp_target_swapchain.c | 64 +++++++-- src/xrt/compositor/main/comp_window_peek.c | 2 +- 4 files changed, 165 insertions(+), 80 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 5d7b14abc..28c2a98d8 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -43,6 +43,20 @@ #include #include #include +#include + + +/* + * + * Small internal helpers. + * + */ + +#define CHAIN(STRUCT, NEXT) \ + do { \ + (STRUCT).pNext = NEXT; \ + NEXT = (VkBaseInStructure *)&(STRUCT); \ + } while (false) /* @@ -85,12 +99,6 @@ struct comp_renderer } mirror_to_debug_gui; - - struct - { - VkSemaphore present_complete; - VkSemaphore render_complete; - } semaphores; //! @} //! @name Image-dependent members @@ -146,27 +154,6 @@ renderer_wait_gpu_idle(struct comp_renderer *r) os_mutex_unlock(&vk->queue_mutex); } -static void -renderer_init_semaphores(struct comp_renderer *r) -{ - struct vk_bundle *vk = &r->c->base.vk; - VkResult ret; - - VkSemaphoreCreateInfo info = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - }; - - ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &r->semaphores.present_complete); - if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vkCreateSemaphore: %s", vk_result_string(ret)); - } - - ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &r->semaphores.render_complete); - if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vkCreateSemaphore: %s", vk_result_string(ret)); - } -} - static void calc_viewport_data(struct comp_renderer *r, struct render_viewport_data *out_l_viewport_data, @@ -568,12 +555,8 @@ renderer_create(struct comp_renderer *r, struct comp_compositor *c) r->acquired_buffer = -1; r->fenced_buffer = -1; - r->semaphores.present_complete = VK_NULL_HANDLE; - r->semaphores.render_complete = VK_NULL_HANDLE; r->rtr_array = NULL; - renderer_init_semaphores(r); - // Try to early-allocate these, in case we can. renderer_ensure_images_and_renderings(r, false); @@ -631,9 +614,9 @@ renderer_submit_queue(struct comp_renderer *r, VkCommandBuffer cmd, VkPipelineSt VkResult ret; -#define WAIT_SEMAPHORE_COUNT 1 - VkPipelineStageFlags stage_flags[WAIT_SEMAPHORE_COUNT] = {pipeline_stage_flag}; - VkSemaphore wait_semaphores[WAIT_SEMAPHORE_COUNT] = {r->semaphores.present_complete}; + /* + * Wait for previous frame's work to complete. + */ // Wait for the last fence, if any. renderer_wait_for_last_fence(r); @@ -645,15 +628,59 @@ renderer_submit_queue(struct comp_renderer *r, VkCommandBuffer cmd, VkPipelineSt COMP_ERROR(r->c, "vkResetFences: %s", vk_result_string(ret)); } + + /* + * Regular semaphore setup. + */ + + struct comp_target *ct = r->c->target; +#define WAIT_SEMAPHORE_COUNT 1 + + VkSemaphore wait_sems[WAIT_SEMAPHORE_COUNT] = {ct->semaphores.present_complete}; + VkPipelineStageFlags stage_flags[WAIT_SEMAPHORE_COUNT] = {pipeline_stage_flag}; + + VkSemaphore *wait_sems_ptr = NULL; + VkPipelineStageFlags *stage_flags_ptr = NULL; + uint32_t wait_sem_count = 0; + if (wait_sems[0] != VK_NULL_HANDLE) { + wait_sems_ptr = wait_sems; + stage_flags_ptr = stage_flags; + wait_sem_count = WAIT_SEMAPHORE_COUNT; + } + + // Next pointer for VkSubmitInfo + const void *next = NULL; + +#ifdef VK_KHR_timeline_semaphore + assert(r->c->frame.rendering.id >= 0); + uint64_t render_complete_signal_values[WAIT_SEMAPHORE_COUNT] = {(uint64_t)r->c->frame.rendering.id}; + + VkTimelineSemaphoreSubmitInfoKHR timeline_info = { + .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR, + }; + + if (ct->semaphores.render_complete_is_timeline) { + timeline_info = (VkTimelineSemaphoreSubmitInfoKHR){ + .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR, + .signalSemaphoreValueCount = WAIT_SEMAPHORE_COUNT, + .pSignalSemaphoreValues = render_complete_signal_values, + }; + + CHAIN(timeline_info, next); + } +#endif + + VkSubmitInfo comp_submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = WAIT_SEMAPHORE_COUNT, - .pWaitSemaphores = wait_semaphores, - .pWaitDstStageMask = stage_flags, + .pNext = next, + .pWaitDstStageMask = stage_flags_ptr, + .pWaitSemaphores = wait_sems_ptr, + .waitSemaphoreCount = wait_sem_count, .commandBufferCount = 1, .pCommandBuffers = &cmd, .signalSemaphoreCount = 1, - .pSignalSemaphores = &r->semaphores.render_complete, + .pSignalSemaphores = &ct->semaphores.render_complete, }; ret = vk_locked_submit(vk, vk->queue, 1, &comp_submit_info, r->fences[r->acquired_buffer]); @@ -722,7 +749,7 @@ renderer_acquire_swapchain_image(struct comp_renderer *r) // Not ready yet. return; } - ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &buffer_index); + ret = comp_target_acquire(r->c->target, &buffer_index); if ((ret == VK_ERROR_OUT_OF_DATE_KHR) || (ret == VK_SUBOPTIMAL_KHR)) { COMP_DEBUG(r->c, "Received %s.", vk_result_string(ret)); @@ -736,7 +763,7 @@ renderer_acquire_swapchain_image(struct comp_renderer *r) } /* Acquire image again to silence validation error */ - ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &buffer_index); + ret = comp_target_acquire(r->c->target, &buffer_index); if (ret != VK_SUCCESS) { COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); } @@ -767,13 +794,16 @@ renderer_present_swapchain_image(struct comp_renderer *r, uint64_t desired_prese VkResult ret; - ret = comp_target_present( // - r->c->target, // - r->c->base.vk.queue, // - r->acquired_buffer, // - r->semaphores.render_complete, // - desired_present_time_ns, // - present_slop_ns); // + assert(r->c->frame.rendering.id >= 0); + uint64_t render_complete_signal_value = (uint64_t)r->c->frame.rendering.id; + + ret = comp_target_present( // + r->c->target, // + r->c->base.vk.queue, // + r->acquired_buffer, // + render_complete_signal_value, // + desired_present_time_ns, // + present_slop_ns); // r->acquired_buffer = -1; if (ret == VK_ERROR_OUT_OF_DATE_KHR || ret == VK_SUBOPTIMAL_KHR) { @@ -798,16 +828,6 @@ renderer_destroy(struct comp_renderer *r) // Command buffers renderer_close_renderings_and_fences(r); - // Semaphores - if (r->semaphores.present_complete != VK_NULL_HANDLE) { - vk->vkDestroySemaphore(vk->device, r->semaphores.present_complete, NULL); - r->semaphores.present_complete = VK_NULL_HANDLE; - } - if (r->semaphores.render_complete != VK_NULL_HANDLE) { - vk->vkDestroySemaphore(vk->device, r->semaphores.render_complete, NULL); - r->semaphores.render_complete = VK_NULL_HANDLE; - } - comp_layer_renderer_destroy(&(r->lr)); u_var_remove_root(r); diff --git a/src/xrt/compositor/main/comp_target.h b/src/xrt/compositor/main/comp_target.h index 9a64dc196..2c20dfedb 100644 --- a/src/xrt/compositor/main/comp_target.h +++ b/src/xrt/compositor/main/comp_target.h @@ -86,6 +86,17 @@ struct comp_target //! Transformation of the current surface, required for pre-rotation VkSurfaceTransformFlagBitsKHR surface_transform; + struct + { + //! Optional semaphore the target should signal when present is complete. + VkSemaphore present_complete; + + //! Semaphore the renderer (consuming this target) should signal when rendering is complete. + VkSemaphore render_complete; + + //! If true, @ref render_complete is a timeline semaphore instead of a binary semaphore + bool render_complete_is_timeline; + } semaphores; /* * @@ -137,19 +148,29 @@ struct comp_target /*! * Acquire the next image for rendering. * + * If @ref semaphores::present_complete is not null, your use of this image should wait on it. + * * @pre @ref has_images returns true */ - VkResult (*acquire)(struct comp_target *ct, VkSemaphore semaphore, uint32_t *out_index); + VkResult (*acquire)(struct comp_target *ct, uint32_t *out_index); /*! * Present the image at index to the screen. * * @pre @ref acquire succeeded for the same @p semaphore and @p index you are passing + * + * @param ct self + * @param queue The Vulkan queue being used + * @param index The swapchain image index to present + * @param timeline_semaphore_value The value to await on @ref semaphores::render_complete if @ref + * semaphores::render_complete_is_timeline is true. + * @param desired_present_time_ns The timestamp to present at, ideally. + * @param present_slop_ns TODO */ VkResult (*present)(struct comp_target *ct, VkQueue queue, uint32_t index, - VkSemaphore semaphore, + uint64_t timeline_semaphore_value, uint64_t desired_present_time_ns, uint64_t present_slop_ns); @@ -300,11 +321,11 @@ comp_target_has_images(struct comp_target *ct) * @ingroup comp_main */ static inline VkResult -comp_target_acquire(struct comp_target *ct, VkSemaphore semaphore, uint32_t *out_index) +comp_target_acquire(struct comp_target *ct, uint32_t *out_index) { COMP_TRACE_MARKER(); - return ct->acquire(ct, semaphore, out_index); + return ct->acquire(ct, out_index); } /*! @@ -317,20 +338,20 @@ static inline VkResult comp_target_present(struct comp_target *ct, VkQueue queue, uint32_t index, - VkSemaphore semaphore, + uint64_t timeline_semaphore_value, uint64_t desired_present_time_ns, uint64_t present_slop_ns) { COMP_TRACE_MARKER(); - return ct->present( // - ct, // - queue, // - index, // - semaphore, // - desired_present_time_ns, // - present_slop_ns); // + return ct->present( // + ct, // + queue, // + index, // + timeline_semaphore_value, // + desired_present_time_ns, // + present_slop_ns); // } /*! diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index b34762491..3b76fce52 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -594,6 +594,46 @@ create_vblank_event_thread(struct comp_target *ct) } #endif +static void +target_fini_semaphores(struct comp_target_swapchain *cts) +{ + struct vk_bundle *vk = get_vk(cts); + + if (cts->base.semaphores.present_complete != VK_NULL_HANDLE) { + vk->vkDestroySemaphore(vk->device, cts->base.semaphores.present_complete, NULL); + cts->base.semaphores.present_complete = VK_NULL_HANDLE; + } + + if (cts->base.semaphores.render_complete != VK_NULL_HANDLE) { + vk->vkDestroySemaphore(vk->device, cts->base.semaphores.render_complete, NULL); + cts->base.semaphores.render_complete = VK_NULL_HANDLE; + } +} + +static void +target_init_semaphores(struct comp_target_swapchain *cts) +{ + struct vk_bundle *vk = get_vk(cts); + VkResult ret; + + target_fini_semaphores(cts); + + VkSemaphoreCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }; + + ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &cts->base.semaphores.present_complete); + if (ret != VK_SUCCESS) { + COMP_ERROR(cts->base.c, "vkCreateSemaphore: %s", vk_result_string(ret)); + } + + cts->base.semaphores.render_complete_is_timeline = false; + ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &cts->base.semaphores.render_complete); + if (ret != VK_SUCCESS) { + COMP_ERROR(cts->base.c, "vkCreateSemaphore: %s", vk_result_string(ret)); + } +} + /* * @@ -628,6 +668,8 @@ comp_target_swapchain_create_images(struct comp_target *ct, // Free old image views. destroy_image_views(cts); + target_init_semaphores(cts); + VkSwapchainKHR old_swapchain_handle = cts->swapchain.handle; cts->base.image_count = 0; @@ -771,7 +813,7 @@ comp_target_swapchain_has_images(struct comp_target *ct) } static VkResult -comp_target_swapchain_acquire_next_image(struct comp_target *ct, VkSemaphore semaphore, uint32_t *out_index) +comp_target_swapchain_acquire_next_image(struct comp_target *ct, uint32_t *out_index) { struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; struct vk_bundle *vk = get_vk(cts); @@ -781,20 +823,20 @@ comp_target_swapchain_acquire_next_image(struct comp_target *ct, VkSemaphore sem return VK_ERROR_INITIALIZATION_FAILED; } - return vk->vkAcquireNextImageKHR( // - vk->device, // device - cts->swapchain.handle, // swapchain - UINT64_MAX, // timeout - semaphore, // semaphore - VK_NULL_HANDLE, // fence - out_index); // pImageIndex + return vk->vkAcquireNextImageKHR( // + vk->device, // device + cts->swapchain.handle, // swapchain + UINT64_MAX, // timeout + cts->base.semaphores.present_complete, // semaphore + VK_NULL_HANDLE, // fence + out_index); // pImageIndex } static VkResult comp_target_swapchain_present(struct comp_target *ct, VkQueue queue, uint32_t index, - VkSemaphore semaphore, + uint64_t timeline_semaphore_value, uint64_t desired_present_time_ns, uint64_t present_slop_ns) { @@ -819,7 +861,7 @@ comp_target_swapchain_present(struct comp_target *ct, .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = vk->has_GOOGLE_display_timing ? &timings : NULL, .waitSemaphoreCount = 1, - .pWaitSemaphores = &semaphore, + .pWaitSemaphores = &cts->base.semaphores.render_complete, .swapchainCount = 1, .pSwapchains = &cts->swapchain.handle, .pImageIndices = &index, @@ -966,6 +1008,8 @@ comp_target_swapchain_cleanup(struct comp_target_swapchain *cts) cts->surface.handle = VK_NULL_HANDLE; } + target_fini_semaphores(cts); + u_pc_destroy(&cts->upc); } diff --git a/src/xrt/compositor/main/comp_window_peek.c b/src/xrt/compositor/main/comp_window_peek.c index 4702b8edb..faeabc6a7 100644 --- a/src/xrt/compositor/main/comp_window_peek.c +++ b/src/xrt/compositor/main/comp_window_peek.c @@ -243,7 +243,7 @@ comp_window_peek_blit(struct comp_window_peek *w, VkImage src, int32_t width, in ; uint32_t current; - VkResult ret = comp_target_acquire(&w->base.base, w->acquire, ¤t); + VkResult ret = comp_target_acquire(&w->base.base, ¤t); if (ret != VK_SUCCESS) { COMP_ERROR(w->c, "comp_target_acquire: %s", vk_result_string(ret)); }