aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgrenderloop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgrenderloop.cpp')
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp71
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()