diff options
author | Aurélien Brooke <[email protected]> | 2025-04-10 11:55:38 +0200 |
---|---|---|
committer | Aurélien Brooke <[email protected]> | 2025-04-30 21:06:03 +0200 |
commit | a343d5fe58343d1b6ee3454fa8aa14965624e040 (patch) | |
tree | f1d58998f145dda3fe54bf83b2ac0cc4b008190a | |
parent | cdeb245340b2f148e888ee28c215f60c80d822e0 (diff) |
rhi: vulkan: bail out if device loss occurs during vkWaitForFences()
The NVIDIA driver may become unstable (including kernel lockups) if
Vulkan API calls continue after a device loss.
Ensure we stop frame processing immediately when vkWaitForFences()
returns VK_ERROR_DEVICE_LOST. Also, don't try to vkWaitForFences() when
calling releaseSwapChainResources() after a device loss.
Change-Id: I2c35a7a7ad07830778b6dc4d40f1ce62535e988a
Reviewed-by: Laszlo Agocs <[email protected]>
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 27 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan_p.h | 2 |
2 files changed, 23 insertions, 6 deletions
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 56195ddd692..54c3500bf82 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2481,7 +2481,7 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain) for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) { QVkSwapChain::FrameResources &frame(swapChainD->frameRes[i]); if (frame.cmdFence) { - if (frame.cmdFenceWaitable) + if (!deviceLost && frame.cmdFenceWaitable) df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX); df->vkDestroyFence(dev, frame.cmdFence, nullptr); frame.cmdFence = VK_NULL_HANDLE; @@ -2581,7 +2581,9 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin // will make B wait for A's frame 0 commands, so if a resource is written // in B's frame or when B checks for pending resource releases, that won't // mess up A's in-flight commands (as they are not in flight anymore). - waitCommandCompletion(frameResIndex); + QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex); + if (waitResult != QRhi::FrameOpSuccess) + return waitResult; if (!frame.imageAcquired) { // move on to next swapchain image @@ -2895,17 +2897,30 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer return QRhi::FrameOpSuccess; } -void QRhiVulkan::waitCommandCompletion(int frameSlot) +QRhi::FrameOpResult QRhiVulkan::waitCommandCompletion(int frameSlot) { for (QVkSwapChain *sc : std::as_const(swapchains)) { const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0; QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]); if (frame.cmdFenceWaitable) { - df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX); + VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX); + + if (err != VK_SUCCESS) { + if (err == VK_ERROR_DEVICE_LOST) { + qWarning("Device loss detected in vkWaitForFences()"); + deviceLost = true; + return QRhi::FrameOpDeviceLost; + } + qWarning("Failed to wait for fence: %d", err); + return QRhi::FrameOpError; + } + df->vkResetFences(dev, 1, &frame.cmdFence); frame.cmdFenceWaitable = false; } } + + return QRhi::FrameOpSuccess; } QRhi::FrameOpResult QRhiVulkan::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags) @@ -2921,7 +2936,9 @@ QRhi::FrameOpResult QRhiVulkan::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT; - waitCommandCompletion(currentFrameSlot); + QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot); + if (waitResult != QRhi::FrameOpSuccess) + return waitResult; ensureCommandPoolForNewFrame(); diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index 140e7bcc4a1..15e866b7c63 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -832,7 +832,7 @@ public: QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb); QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence, VkSemaphore *waitSem, VkSemaphore *signalSem); - void waitCommandCompletion(int frameSlot); + QRhi::FrameOpResult waitCommandCompletion(int frameSlot); VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const; using BufferImageCopyList = QVarLengthArray<VkBufferImageCopy, 16>; void prepareUploadSubres(QVkTexture *texD, int layer, int level, |