diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-11-27 13:56:27 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-11-28 10:55:15 +0100 |
commit | 77a5b336fc7dbb16840e6b2ec86365c2f5e979c6 (patch) | |
tree | 334105ac942f24b46fb526441c6db2589fd2ba59 /src | |
parent | a26792aef8a19432748b453fe09bf0579c4dd1c1 (diff) |
Prevent infinite rhi init failure in threaded render loop
Task-number: QTBUG-80365
Change-Id: I929fb76eb8d023ab048f6d1c91be078de3cfe750
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 3 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgrenderloop_p.h | 5 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgthreadedrenderloop.cpp | 42 |
4 files changed, 41 insertions, 11 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 40872866df..d927e27af8 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1768,6 +1768,8 @@ bool QQuickWindow::event(QEvent *e) if (e->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)) update(); + else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure)) + d->windowManager->handleContextCreationFailure(this, false); return QWindow::event(e); } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index d104085eb0..ace8d627e1 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -112,7 +112,8 @@ public: Q_DECLARE_PUBLIC(QQuickWindow) enum CustomEvents { - FullUpdateRequest = QEvent::User + 1 + FullUpdateRequest = QEvent::User + 1, + TriggerContextCreationFailure = QEvent::User + 2 }; static inline QQuickWindowPrivate *get(QQuickWindow *c) { return c->d_func(); } diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 02d0b84de1..e720a3636b 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -112,12 +112,11 @@ public: static void cleanup(); + void handleContextCreationFailure(QQuickWindow *window, bool isEs); + Q_SIGNALS: void timeToIncubate(); -protected: - void handleContextCreationFailure(QQuickWindow *window, bool isEs); - private: static QSGRenderLoop *s_instance; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index c27ec5a263..6f842e59c5 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -368,6 +368,9 @@ public: QSize windowSize; float dpr = 1; int rhiSampleCount = 1; + bool rhiDeviceLost = false; + bool rhiDoomed = false; + bool guiNotifiedAboutRhiFailure = false; // Local event queue stuff... bool stopEventProcessing; @@ -622,13 +625,15 @@ void QSGRenderThread::sync(bool inExpose, bool inGrab) sgrc->initialize(&rcParams); } } - } else { + } else if (rhi) { // With the rhi making the (OpenGL) context current serves only one // purpose: to enable external OpenGL rendering connected to one of // the QQuickWindow signals (beforeSynchronizing, beforeRendering, // etc.) to function like it did on the direct OpenGL path. For our // own rendering this call would not be necessary. rhi->makeThreadLocalNativeContextCurrent(); + } else { + current = false; } if (current) { QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); @@ -669,6 +674,7 @@ void QSGRenderThread::handleDeviceLoss() QQuickWindowPrivate::get(window)->cleanupNodesOnShutdown(); sgrc->invalidate(); wm->releaseSwapchain(window); + rhiDeviceLost = true; delete rhi; rhi = nullptr; } @@ -771,7 +777,7 @@ void QSGRenderThread::syncAndRender(QImage *grabImage) QQuickProfiler::SceneGraphRenderLoopSync); if (!syncResultedInChanges && !repaintRequested && sgrc->isValid() && !grabImage) { - if (gl || !rhi->isRecordingFrame()) { + if (gl || (rhi && !rhi->isRecordingFrame())) { qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- no changes, render aborted"); int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) @@ -790,10 +796,10 @@ void QSGRenderThread::syncAndRender(QImage *grabImage) } bool current = true; - if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0) { + if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0 && (gl || rhi)) { if (gl) current = gl->makeCurrent(window); - else if (rhi) + else rhi->makeThreadLocalNativeContextCurrent(); } else { current = false; @@ -912,14 +918,21 @@ void QSGRenderThread::processEventsAndWaitForMore() void QSGRenderThread::ensureRhi() { if (!rhi) { + if (rhiDoomed) // no repeated attempts if the initial attempt failed + return; QSGRhiSupport *rhiSupport = QSGRhiSupport::instance(); rhi = rhiSupport->createRhi(window, offscreenSurface); if (rhi) { + rhiDeviceLost = false; rhiSampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, rhi); if (rhiSupport->isProfilingRequested()) QSGRhiProfileConnection::instance()->initialize(rhi); // ### this breaks down with multiple windows } else { - qWarning("Failed to create QRhi on the render thread; scenegraph is not functional"); + if (!rhiDeviceLost) { + rhiDoomed = true; + qWarning("Failed to create QRhi on the render thread; scenegraph is not functional"); + } + // otherwise no error, will retry on a subsequent rendering attempt return; } } @@ -975,9 +988,24 @@ void QSGRenderThread::run() if (window) { if (enableRhi) { + ensureRhi(); - if (rhi) - syncAndRender(); + + // We absolutely have to syncAndRender() here, even when QRhi + // failed to initialize otherwise the gui thread will be left + // in a blocked state. It is up to syncAndRender() to + // gracefully skip all graphics stuff when rhi is null. + + syncAndRender(); + + // Now we can do something about rhi init failures. (reinit + // failure after device reset does not count) + if (rhiDoomed && !guiNotifiedAboutRhiFailure) { + guiNotifiedAboutRhiFailure = true; + QEvent *e = new QEvent(QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure)); + QCoreApplication::postEvent(window, e); + } + } else { if (!sgrc->openglContext() && windowSize.width() > 0 && windowSize.height() > 0 && gl->makeCurrent(window)) { QSGDefaultRenderContext::InitParams rcParams; |