Rework semaphores for presentation to be created per swap chain image to fix validation error.

This commit is contained in:
Dario 2025-05-14 15:20:33 -03:00
parent 428a762e98
commit ad22f65489
2 changed files with 27 additions and 31 deletions

View file

@ -2683,8 +2683,10 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu
if (p_cmd_buffers.size() > 0) {
thread_local LocalVector<VkCommandBuffer> command_buffers;
thread_local LocalVector<VkSemaphore> present_semaphores;
thread_local LocalVector<VkSemaphore> signal_semaphores;
command_buffers.clear();
present_semaphores.clear();
signal_semaphores.clear();
for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {
@ -2696,27 +2698,11 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu
signal_semaphores.push_back(VkSemaphore(p_cmd_semaphores[i].id));
}
VkSemaphore present_semaphore = VK_NULL_HANDLE;
if (p_swap_chains.size() > 0) {
if (command_queue->present_semaphores.is_empty()) {
// Create the semaphores used for presentation if they haven't been created yet.
VkSemaphore semaphore = VK_NULL_HANDLE;
VkSemaphoreCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
for (uint32_t i = 0; i < frame_count; i++) {
err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore);
ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED);
command_queue->present_semaphores.push_back(semaphore);
}
}
// If a presentation semaphore is required, cycle across the ones available on the queue. It is technically possible
// and valid to reuse the same semaphore for this particular operation, but we create multiple ones anyway in case
// some hardware expects multiple semaphores to be used.
present_semaphore = command_queue->present_semaphores[command_queue->present_semaphore_index];
signal_semaphores.push_back(present_semaphore);
command_queue->present_semaphore_index = (command_queue->present_semaphore_index + 1) % command_queue->present_semaphores.size();
for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
const SwapChain *swap_chain = (const SwapChain *)(p_swap_chains[i].id);
VkSemaphore semaphore = swap_chain->present_semaphores[swap_chain->image_index];
present_semaphores.push_back(semaphore);
signal_semaphores.push_back(semaphore);
}
VkSubmitInfo submit_info = {};
@ -2750,10 +2736,9 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu
command_queue->pending_semaphores_for_fence.clear();
}
if (present_semaphore != VK_NULL_HANDLE) {
if (!present_semaphores.is_empty()) {
// If command buffers were executed, swap chains must wait on the present semaphore used by the command queue.
wait_semaphores.clear();
wait_semaphores.push_back(present_semaphore);
wait_semaphores = present_semaphores;
}
}
@ -2838,11 +2823,6 @@ void RenderingDeviceDriverVulkan::command_queue_free(CommandQueueID p_cmd_queue)
CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id);
// Erase all the semaphores used for presentation.
for (VkSemaphore semaphore : command_queue->present_semaphores) {
vkDestroySemaphore(vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE));
}
// Erase all the semaphores used for image acquisition.
for (VkSemaphore semaphore : command_queue->image_semaphores) {
vkDestroySemaphore(vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE));
@ -3024,6 +3004,12 @@ void RenderingDeviceDriverVulkan::_swap_chain_release(SwapChain *swap_chain) {
swap_chain->command_queues_acquired.clear();
swap_chain->command_queues_acquired_semaphores.clear();
for (VkSemaphore semaphore : swap_chain->present_semaphores) {
vkDestroySemaphore(vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE));
}
swap_chain->present_semaphores.clear();
}
RenderingDeviceDriver::SwapChainID RenderingDeviceDriverVulkan::swap_chain_create(RenderingContextDriver::SurfaceID p_surface) {
@ -3360,6 +3346,17 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
swap_chain->framebuffers.push_back(RDD::FramebufferID(framebuffer));
}
VkSemaphore vk_semaphore = VK_NULL_HANDLE;
for (uint32_t i = 0; i < image_count; i++) {
VkSemaphoreCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &vk_semaphore);
ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED);
swap_chain->present_semaphores.push_back(vk_semaphore);
}
// Once everything's been created correctly, indicate the surface no longer needs to be resized.
context_driver->surface_set_needs_resize(swap_chain->surface, false);