c/main: Move ownership of present/render semaphores to comp_target

Co-authored-by: Jakob Bornecrantz <jakob@collabora.com>
This commit is contained in:
Ryan Pavlik 2022-09-28 21:34:06 +00:00 committed by Jakob Bornecrantz
parent 3b7f95b39e
commit 109e373e0c
4 changed files with 165 additions and 80 deletions

View file

@ -43,6 +43,20 @@
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <inttypes.h>
/*
*
* 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);

View file

@ -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); //
}
/*!

View file

@ -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);
}

View file

@ -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, &current);
VkResult ret = comp_target_acquire(&w->base.base, &current);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c, "comp_target_acquire: %s", vk_result_string(ret));
}