From 10ee6eace315b4f5d697c491291f7e3adf8d28a2 Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Mon, 26 Aug 2024 15:43:15 +0300 Subject: [PATCH] vk: Create more image semaphores that command buffers used. Mostly workaround for vkAcquireNextImageKHR errors, Create more cmdbuffers with slow vulkan implementation could produce issues when old cmdbuffer is not finished but need to resize dynamic buffer. Based on ``` Added additional image ready semaphore - this addresses validation errors when calling vkAcquireNextImageKHR() which started appearing in SDK 1.3.275 ``` https://github.com/kondrak/vkQuake2/commit/88009a6149a3257630fdb5b7554238da9199e22e --- src/client/refresh/vk/header/qvk.h | 4 +++- src/client/refresh/vk/vk_common.c | 35 +++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/client/refresh/vk/header/qvk.h b/src/client/refresh/vk/header/qvk.h index d452432f..06409698 100644 --- a/src/client/refresh/vk/header/qvk.h +++ b/src/client/refresh/vk/header/qvk.h @@ -211,8 +211,10 @@ typedef enum } qvkrenderpasstype_t; // Vulkan constants: command and dynamic buffer count -#define NUM_CMDBUFFERS 32 +#define NUM_CMDBUFFERS 2 #define NUM_DYNBUFFERS 2 +// Vulkan constants: number of image semaphores (introduced with VulkanSDK 1.3.275) +#define NUM_IMG_SEMAPHORES (NUM_CMDBUFFERS * 2) #define PUSH_CONSTANT_VERTEX_SIZE 17 #define PUSH_CONSTANT_FRAGMENT_SIZE 11 diff --git a/src/client/refresh/vk/vk_common.c b/src/client/refresh/vk/vk_common.c index c07ae956..2f1c04f8 100644 --- a/src/client/refresh/vk/vk_common.c +++ b/src/client/refresh/vk/vk_common.c @@ -89,7 +89,7 @@ qvkrenderpass_t vk_renderpasses[RP_COUNT] = { VkCommandPool vk_commandPool[NUM_CMDBUFFERS] = { 0 }; VkCommandPool vk_transferCommandPool = VK_NULL_HANDLE; VkDescriptorPool vk_descriptorPool = VK_NULL_HANDLE; -static VkCommandPool vk_stagingCommandPool[NUM_DYNBUFFERS] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; +static VkCommandPool vk_stagingCommandPool[NUM_DYNBUFFERS] = { 0 }; // Vulkan image views static VkImageView *vk_imageviews = NULL; // Vulkan framebuffers @@ -113,7 +113,7 @@ static VkCommandBuffer *vk_commandbuffers = NULL; // command buffer double buffering fences static VkFence vk_fences[NUM_CMDBUFFERS]; // semaphore: signal when next image is available for rendering -static VkSemaphore vk_imageAvailableSemaphores[NUM_CMDBUFFERS]; +static VkSemaphore vk_imageAvailableSemaphores[NUM_IMG_SEMAPHORES]; // semaphore: signal when rendering to current command buffer is complete static VkSemaphore vk_renderFinishedSemaphores[NUM_CMDBUFFERS]; // tracker variables @@ -122,6 +122,8 @@ VkCommandBuffer vk_activeCmdbuffer = VK_NULL_HANDLE; int vk_activeBufferIdx = 0; // index of currently acquired image static uint32_t vk_imageIndex = 0; +// index of currently used image semaphore +uint32_t vk_imageSemaphoreIdx = 0; // index of currently used staging buffer static int vk_activeStagingBuffer = 0; // started rendering frame? @@ -1645,9 +1647,15 @@ void QVk_Shutdown( void ) } if (vk_device.logical != VK_NULL_HANDLE) { - for (int i = 0; i < NUM_CMDBUFFERS; ++i) + int i; + + for (i = 0; i < NUM_IMG_SEMAPHORES; ++i) { vkDestroySemaphore(vk_device.logical, vk_imageAvailableSemaphores[i], NULL); + } + + for (i = 0; i < NUM_CMDBUFFERS; ++i) + { vkDestroySemaphore(vk_device.logical, vk_renderFinishedSemaphores[i], NULL); vkDestroyFence(vk_device.logical, vk_fences[i], NULL); } @@ -2018,6 +2026,12 @@ qboolean QVk_Init(void) vk_scissor.offset.y = 0; vk_scissor.extent = vk_swapchain.extent; + + for (i = 0; i < NUM_DYNBUFFERS; i++ ) + { + vk_stagingCommandPool[i] = VK_NULL_HANDLE; + } + // setup fences and semaphores VkFenceCreateInfo fCreateInfo = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, @@ -2029,20 +2043,24 @@ qboolean QVk_Init(void) .pNext = NULL, .flags = 0 }; + for (i = 0; i < NUM_CMDBUFFERS; ++i) { vk_commandPool[i] = VK_NULL_HANDLE; VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo, NULL, &vk_fences[i])); - VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_imageAvailableSemaphores[i])); VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_renderFinishedSemaphores[i])); QVk_DebugSetObjectName((uint64_t)vk_fences[i], VK_OBJECT_TYPE_FENCE, va("Fence #%d", i)); - QVk_DebugSetObjectName((uint64_t)vk_imageAvailableSemaphores[i], - VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: image available #%d", i)); QVk_DebugSetObjectName((uint64_t)vk_renderFinishedSemaphores[i], VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: render finished #%d", i)); } + for (i = 0; i < NUM_IMG_SEMAPHORES; ++i) + { + VK_VERIFY(vkCreateSemaphore(vk_device.logical, &sCreateInfo, NULL, &vk_imageAvailableSemaphores[i])); + + QVk_DebugSetObjectName((uint64_t)vk_imageAvailableSemaphores[i], VK_OBJECT_TYPE_SEMAPHORE, va("Semaphore: image available #%d", i)); + } R_Printf(PRINT_ALL, "...created synchronization objects\n"); // setup render passes @@ -2185,7 +2203,7 @@ VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor) ReleaseSwapBuffers(); VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, 500000000 /* 0.5 sec */, - vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex); + vk_imageAvailableSemaphores[vk_imageSemaphoreIdx], VK_NULL_HANDLE, &vk_imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR || result == VK_TIMEOUT) { vk_recreateSwapchainNeeded = true; @@ -2264,7 +2282,7 @@ VkResult QVk_EndFrame(qboolean force) VkSubmitInfo submitInfo = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .waitSemaphoreCount = 1, - .pWaitSemaphores = &vk_imageAvailableSemaphores[vk_activeBufferIdx], + .pWaitSemaphores = &vk_imageAvailableSemaphores[vk_imageSemaphoreIdx], .signalSemaphoreCount = 1, .pSignalSemaphores = &vk_renderFinishedSemaphores[vk_activeBufferIdx], .pWaitDstStageMask = &waitStages, @@ -2299,6 +2317,7 @@ VkResult QVk_EndFrame(qboolean force) } vk_activeBufferIdx = (vk_activeBufferIdx + 1) % NUM_CMDBUFFERS; + vk_imageSemaphoreIdx = (vk_imageSemaphoreIdx + 1) % NUM_IMG_SEMAPHORES; vk_frameStarted = false; return renderResult;