diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-09-12 11:02:43 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-09-23 12:50:01 +0200 |
commit | 5f4b7f37a430135cbbf930373e0e9682e9a3a2ac (patch) | |
tree | 9845e33fbe910524fc1ad923fc542572f2697129 /src/quick/scenegraph | |
parent | d3817f4b0b42b180b36c3c5afb22eb592a7e2a91 (diff) |
Handle rhi device loss in the basic render loop
Change-Id: I02cee05ce7eee2ad1c458d1a934c210c12d1dea2
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
Diffstat (limited to 'src/quick/scenegraph')
-rw-r--r-- | src/quick/scenegraph/qsgrenderloop.cpp | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 25d10d37d4..a5b5fe04f5 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -190,6 +190,7 @@ public: QSGRenderContext *createRenderContext(QSGContext *) const override { return rc; } void releaseSwapchain(QQuickWindow *window); + void handleDeviceLoss(); bool eventFilter(QObject *watched, QEvent *event) override; @@ -438,6 +439,25 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) delete d->animationController; } +void QSGGuiThreadRenderLoop::handleDeviceLoss() +{ + if (!rhi || !rhi->isDeviceLost()) + return; + + qWarning("Graphics device lost, cleaning up scenegraph and releasing RHI"); + + for (auto it = m_windows.constBegin(), itEnd = m_windows.constEnd(); it != itEnd; ++it) + QQuickWindowPrivate::get(it.key())->cleanupNodesOnShutdown(); + + rc->invalidate(); + + for (auto it = m_windows.constBegin(), itEnd = m_windows.constEnd(); it != itEnd; ++it) + releaseSwapchain(it.key()); + + delete rhi; + rhi = nullptr; +} + void QSGGuiThreadRenderLoop::releaseSwapchain(QQuickWindow *window) { QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); @@ -488,8 +508,11 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) const bool enableRhi = rhiSupport->isRhiEnabled(); if (enableRhi && !rhi) { - offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window); + if (!offscreenSurface) + offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window); + rhi = rhiSupport->createRhi(window, offscreenSurface); + if (rhi) { if (rhiSupport->isProfilingRequested()) QSGRhiProfileConnection::instance()->initialize(rhi); @@ -643,13 +666,19 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) { if (cd->swapchainJustBecameRenderable) qCDebug(QSG_LOG_RENDERLOOP, "just became exposed"); - cd->swapchainJustBecameRenderable = false; - cd->depthStencilForSwapchain->setPixelSize(effectiveOutputSize); + cd->depthStencilForSwapchain->setPixelSize(effectiveOutputSize); cd->depthStencilForSwapchain->build(); + cd->hasActiveSwapchain = cd->swapchain->buildOrResize(); + if (!cd->hasActiveSwapchain && rhi->isDeviceLost()) { + handleDeviceLoss(); + return; + } + cd->swapchainJustBecameRenderable = false; cd->hasRenderableSwapchain = cd->hasActiveSwapchain; + if (!cd->hasActiveSwapchain) qWarning("Failed to build or resize swapchain"); else @@ -662,7 +691,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) QRhi::FrameOpResult frameResult = rhi->beginFrame(cd->swapchain, frameFlags); if (frameResult != QRhi::FrameOpSuccess) { if (frameResult == QRhi::FrameOpDeviceLost) - qWarning("Device lost"); + handleDeviceLoss(); else if (frameResult == QRhi::FrameOpError) qWarning("Failed to start frame"); // out of date is not worth warning about - it may happen even during resizing on some platforms @@ -701,7 +730,13 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) QRhi::EndFrameFlags flags = 0; if (!needsPresent) flags |= QRhi::SkipPresent; - rhi->endFrame(cd->swapchain, flags); + QRhi::FrameOpResult frameResult = rhi->endFrame(cd->swapchain, flags); + if (frameResult != QRhi::FrameOpSuccess) { + if (frameResult == QRhi::FrameOpDeviceLost) + handleDeviceLoss(); + else if (frameResult == QRhi::FrameOpError) + qWarning("Failed to end frame"); + } } else if (needsPresent) { if (!cd->customRenderStage || !cd->customRenderStage->swap()) gl->swapBuffers(window); |