Bug 5056041: Fix the VUID-vkAcquireNextImageKHR-semaphore-01779 error of simpleVulkan

This commit is contained in:
Shawn Zeng 2025-12-22 18:56:23 +08:00
parent 37dcb9b61d
commit 5b2dd19a21
2 changed files with 39 additions and 12 deletions

View File

@ -144,8 +144,9 @@ VulkanBaseApp::~VulkanBaseApp()
} }
#ifdef _VK_TIMELINE_SEMAPHORE #ifdef _VK_TIMELINE_SEMAPHORE
if (m_vkPresentationSemaphore != VK_NULL_HANDLE) { for (size_t i = 0; i < m_vkImageAcquiredSemaphores.size(); i++) {
vkDestroySemaphore(m_device, m_vkPresentationSemaphore, nullptr); vkDestroySemaphore(m_device, m_vkImageAcquiredSemaphores[i], nullptr);
vkDestroySemaphore(m_device, m_vkRenderCompleteSemaphores[i], nullptr);
} }
#endif /* _VK_TIMELINE_SEMAPHORE */ #endif /* _VK_TIMELINE_SEMAPHORE */
@ -1351,8 +1352,15 @@ void VulkanBaseApp::createSyncObjects()
} }
#ifdef _VK_TIMELINE_SEMAPHORE #ifdef _VK_TIMELINE_SEMAPHORE
if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_vkPresentationSemaphore) != VK_SUCCESS) { m_vkImageAcquiredSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
throw std::runtime_error("Failed to create binary semaphore!"); m_vkRenderCompleteSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_vkImageAcquiredSemaphores[i]) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image acquired semaphore!");
}
if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_vkRenderCompleteSemaphores[i]) != VK_SUCCESS) {
throw std::runtime_error("Failed to create render complete semaphore!");
}
} }
#endif /* _VK_TIMELINE_SEMAPHORE */ #endif /* _VK_TIMELINE_SEMAPHORE */
} }
@ -1634,6 +1642,12 @@ void VulkanBaseApp::drawFrame()
static uint64_t waitValue = 0; static uint64_t waitValue = 0;
static uint64_t signalValue = 1; static uint64_t signalValue = 1;
size_t currentFrameIdx = m_currentFrame % MAX_FRAMES_IN_FLIGHT;
// Wait for this frame's fence to avoid VUID-vkAcquireNextImageKHR-semaphore-01779
// Ensures previous frame's GPU work completes before reusing per-frame semaphores
vkWaitForFences(m_device, 1, &m_inFlightFences[currentFrameIdx], VK_TRUE, std::numeric_limits<uint64_t>::max());
VkSemaphoreWaitInfo semaphoreWaitInfo = {}; VkSemaphoreWaitInfo semaphoreWaitInfo = {};
semaphoreWaitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; semaphoreWaitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;
semaphoreWaitInfo.pSemaphores = &m_vkTimelineSemaphore; semaphoreWaitInfo.pSemaphores = &m_vkTimelineSemaphore;
@ -1641,20 +1655,26 @@ void VulkanBaseApp::drawFrame()
semaphoreWaitInfo.pValues = &waitValue; semaphoreWaitInfo.pValues = &waitValue;
vkWaitSemaphores(m_device, &semaphoreWaitInfo, std::numeric_limits<uint64_t>::max()); vkWaitSemaphores(m_device, &semaphoreWaitInfo, std::numeric_limits<uint64_t>::max());
// Use separate binary semaphores for swapchain sync to avoid VUID-01779
// Timeline semaphore (m_vkTimelineSemaphore) is dedicated to Vulkan-CUDA interop
uint32_t imageIndex; uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(m_device, VkResult result = vkAcquireNextImageKHR(m_device,
m_swapChain, m_swapChain,
std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(),
m_vkPresentationSemaphore, m_vkImageAcquiredSemaphores[currentFrameIdx],
VK_NULL_HANDLE, VK_NULL_HANDLE,
&imageIndex); &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain(); recreateSwapChain();
return;
} }
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
throw std::runtime_error("Failed to acquire swap chain image!"); throw std::runtime_error("Failed to acquire swap chain image!");
} }
// Reset the fence for this frame
vkResetFences(m_device, 1, &m_inFlightFences[currentFrameIdx]);
updateUniformBuffer(imageIndex); updateUniformBuffer(imageIndex);
VkSubmitInfo submitInfo = {}; VkSubmitInfo submitInfo = {};
@ -1663,6 +1683,8 @@ void VulkanBaseApp::drawFrame()
std::vector<VkSemaphore> waitSemaphores; std::vector<VkSemaphore> waitSemaphores;
std::vector<VkPipelineStageFlags> waitStages; std::vector<VkPipelineStageFlags> waitStages;
waitSemaphores.push_back(m_vkImageAcquiredSemaphores[currentFrameIdx]);
waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
waitSemaphores.push_back(m_vkTimelineSemaphore); waitSemaphores.push_back(m_vkTimelineSemaphore);
waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
@ -1675,26 +1697,30 @@ void VulkanBaseApp::drawFrame()
std::vector<VkSemaphore> signalSemaphores; std::vector<VkSemaphore> signalSemaphores;
signalSemaphores.push_back(m_vkTimelineSemaphore); signalSemaphores.push_back(m_vkTimelineSemaphore);
signalSemaphores.push_back(m_vkRenderCompleteSemaphores[currentFrameIdx]);
submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.size(); submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.size();
submitInfo.pSignalSemaphores = signalSemaphores.data(); submitInfo.pSignalSemaphores = signalSemaphores.data();
VkTimelineSemaphoreSubmitInfo timelineInfo = {}; VkTimelineSemaphoreSubmitInfo timelineInfo = {};
timelineInfo.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; timelineInfo.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
timelineInfo.waitSemaphoreValueCount = 1; timelineInfo.waitSemaphoreValueCount = 2;
timelineInfo.pWaitSemaphoreValues = &waitValue; uint64_t waitValues[] = {0, waitValue};
timelineInfo.signalSemaphoreValueCount = 1; timelineInfo.pWaitSemaphoreValues = waitValues;
timelineInfo.pSignalSemaphoreValues = &signalValue; timelineInfo.signalSemaphoreValueCount = 2;
uint64_t signalValues[] = {signalValue, 0};
timelineInfo.pSignalSemaphoreValues = signalValues;
submitInfo.pNext = &timelineInfo; submitInfo.pNext = &timelineInfo;
if (vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) { // Submit with fence to track when this frame completes
if (vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_inFlightFences[currentFrameIdx]) != VK_SUCCESS) {
throw std::runtime_error("failed to submit draw command buffer!"); throw std::runtime_error("failed to submit draw command buffer!");
} }
VkPresentInfoKHR presentInfo = {}; VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1; presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &m_vkPresentationSemaphore; presentInfo.pWaitSemaphores = &m_vkRenderCompleteSemaphores[currentFrameIdx];
VkSwapchainKHR swapChains[] = {m_swapChain}; VkSwapchainKHR swapChains[] = {m_swapChain};
presentInfo.swapchainCount = 1; presentInfo.swapchainCount = 1;

View File

@ -107,7 +107,8 @@ protected:
std::vector<VkFence> m_inFlightFences; std::vector<VkFence> m_inFlightFences;
std::vector<VkBuffer> m_uniformBuffers; std::vector<VkBuffer> m_uniformBuffers;
std::vector<VkDeviceMemory> m_uniformMemory; std::vector<VkDeviceMemory> m_uniformMemory;
VkSemaphore m_vkPresentationSemaphore; std::vector<VkSemaphore> m_vkImageAcquiredSemaphores;
std::vector<VkSemaphore> m_vkRenderCompleteSemaphores;
VkSemaphore m_vkTimelineSemaphore; VkSemaphore m_vkTimelineSemaphore;
VkDescriptorSetLayout m_descriptorSetLayout; VkDescriptorSetLayout m_descriptorSetLayout;
VkDescriptorPool m_descriptorPool; VkDescriptorPool m_descriptorPool;