diff options
Diffstat (limited to 'src/quick/scenegraph/qsgrenderloop.cpp')
-rw-r--r-- | src/quick/scenegraph/qsgrenderloop.cpp | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index e620a22fb7..3c8da0fc6a 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -40,6 +40,18 @@ extern bool qsg_useConsistentTiming(); #define ENABLE_DEFAULT_BACKEND +Q_TRACE_POINT(qtquick, QSG_renderWindow_entry) +Q_TRACE_POINT(qtquick, QSG_renderWindow_exit) +Q_TRACE_POINT(qtquick, QSG_polishItems_entry) +Q_TRACE_POINT(qtquick, QSG_polishItems_exit) +Q_TRACE_POINT(qtquick, QSG_sync_entry) +Q_TRACE_POINT(qtquick, QSG_sync_exit) +Q_TRACE_POINT(qtquick, QSG_render_entry) +Q_TRACE_POINT(qtquick, QSG_render_exit) +Q_TRACE_POINT(qtquick, QSG_swap_entry) +Q_TRACE_POINT(qtquick, QSG_swap_exit) + + /* - Uses one QRhi per window. (and so each window has its own QOpenGLContext or ID3D11Device(Context) etc.) - Animations are advanced using the standard timer (no custom animation @@ -126,6 +138,7 @@ public: void releaseSwapchain(QQuickWindow *window); void handleDeviceLoss(); + void teardownGraphics(); bool eventFilter(QObject *watched, QEvent *event) override; @@ -154,6 +167,8 @@ public: mutable QSet<QSGRenderContext *> pendingRenderContexts; bool m_inPolish = false; + + bool swRastFallbackDueToSwapchainFailure = false; }; #endif @@ -246,6 +261,15 @@ void QSGRenderLoop::setInstance(QSGRenderLoop *instance) void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window) { + // Must always be called on the gui thread. + + // Guard for recursion; relevant due to the MessageBox() on Windows. + static QSet<QQuickWindow *> recurseGuard; + if (recurseGuard.contains(window)) + return; + + recurseGuard.insert(window); + QString translatedMessage; QString untranslatedMessage; QQuickWindowPrivate::rhiCreationFailureMessage(QSGRhiSupport::instance()->rhiBackendName(), @@ -266,6 +290,8 @@ void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window) #endif // Q_OS_WIN if (!signalEmitted) qFatal("%s", qPrintable(untranslatedMessage)); + + recurseGuard.remove(window); } #ifdef ENABLE_DEFAULT_BACKEND @@ -354,13 +380,28 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) } } +void QSGGuiThreadRenderLoop::teardownGraphics() +{ + for (auto it = m_windows.begin(), itEnd = m_windows.end(); it != itEnd; ++it) { + if (it->rhi) { + QQuickWindowPrivate::get(it.key())->cleanupNodesOnShutdown(); + if (it->rc) + it->rc->invalidate(); + releaseSwapchain(it.key()); + if (it->ownRhi) + QSGRhiSupport::instance()->destroyRhi(it->rhi, {}); + it->rhi = nullptr; + } + } +} + void QSGGuiThreadRenderLoop::handleDeviceLoss() { qWarning("Graphics device lost, cleaning up scenegraph and releasing RHIs"); for (auto it = m_windows.begin(), itEnd = m_windows.end(); it != itEnd; ++it) { if (!it->rhi || !it->rhi->isDeviceLost()) - return; + continue; QQuickWindowPrivate::get(it.key())->cleanupNodesOnShutdown(); @@ -424,7 +465,8 @@ bool QSGGuiThreadRenderLoop::ensureRhi(QQuickWindow *window, WindowData &data) if (!offscreenSurface) offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window); - QSGRhiSupport::RhiCreateResult rhiResult = rhiSupport->createRhi(window, offscreenSurface); + const bool forcePreferSwRenderer = swRastFallbackDueToSwapchainFailure; + QSGRhiSupport::RhiCreateResult rhiResult = rhiSupport->createRhi(window, offscreenSurface, forcePreferSwRenderer); data.rhi = rhiResult.rhi; data.ownRhi = rhiResult.own; @@ -496,7 +538,7 @@ bool QSGGuiThreadRenderLoop::ensureRhi(QQuickWindow *window, WindowData &data) cd->swapchain->setDepthStencil(cd->depthStencilForSwapchain); } cd->swapchain->setWindow(window); - rhiSupport->applySwapChainFormat(cd->swapchain); + rhiSupport->applySwapChainFormat(cd->swapchain, window); qCDebug(QSG_LOG_INFO, "MSAA sample count for the swapchain is %d. Alpha channel requested = %s", data.sampleCount, alpha ? "yes" : "no"); cd->swapchain->setSampleCount(data.sampleCount); @@ -591,15 +633,24 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) // signals and want to do graphics stuff already there. if (cd->swapchain) { Q_ASSERT(!effectiveOutputSize.isEmpty()); + QSGRhiSupport *rhiSupport = QSGRhiSupport::instance(); const QSize previousOutputSize = cd->swapchain->currentPixelSize(); if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) { if (cd->swapchainJustBecameRenderable) qCDebug(QSG_LOG_RENDERLOOP, "just became exposed"); cd->hasActiveSwapchain = cd->swapchain->createOrResize(); - if (!cd->hasActiveSwapchain && data.rhi->isDeviceLost()) { - handleDeviceLoss(); - return; + if (!cd->hasActiveSwapchain) { + if (data.rhi->isDeviceLost()) { + handleDeviceLoss(); + return; + } else if (previousOutputSize.isEmpty() && !swRastFallbackDueToSwapchainFailure && rhiSupport->attemptReinitWithSwRastUponFail()) { + qWarning("Failed to create swapchain." + " Retrying by requesting a software rasterizer, if applicable for the 3D API implementation."); + swRastFallbackDueToSwapchainFailure = true; + teardownGraphics(); + return; + } } cd->swapchainJustBecameRenderable = false; @@ -659,6 +710,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) Q_TRACE(QSG_swap_entry); const bool needsPresent = alsoSwap && window->isVisible(); + double lastCompletedGpuTime = 0; if (cd->swapchain) { QRhi::EndFrameFlags flags; if (!needsPresent) @@ -669,6 +721,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) handleDeviceLoss(); else if (frameResult == QRhi::FrameOpError) qWarning("Failed to end frame"); + } else { + lastCompletedGpuTime = cd->swapchain->currentFrameCommandBuffer()->lastCompletedGpuTime(); } } if (needsPresent) @@ -694,6 +748,11 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) int((renderTime - syncTime) / 1000000), int((swapTime - renderTime) / 1000000), int(data.timeBetweenRenders.restart())); + if (!qFuzzyIsNull(lastCompletedGpuTime) && cd->graphicsConfig.timestampsEnabled()) { + qCDebug(QSG_LOG_TIME_RENDERLOOP, "[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms", + window, + lastCompletedGpuTime * 1000.0); + } } // Might have been set during syncSceneGraph() |