summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurĂ©lien Brooke <[email protected]>2025-04-10 11:55:38 +0200
committerAurĂ©lien Brooke <[email protected]>2025-04-30 21:06:03 +0200
commita343d5fe58343d1b6ee3454fa8aa14965624e040 (patch)
treef1d58998f145dda3fe54bf83b2ac0cc4b008190a
parentcdeb245340b2f148e888ee28c215f60c80d822e0 (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.cpp27
-rw-r--r--src/gui/rhi/qrhivulkan_p.h2
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,