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.cpp390
1 files changed, 330 insertions, 60 deletions
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 2e91bafa7c..d38b5649c7 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -40,6 +40,7 @@
#include "qsgrenderloop_p.h"
#include "qsgthreadedrenderloop_p.h"
#include "qsgwindowsrenderloop_p.h"
+#include "qsgrhisupport_p.h"
#include <private/qquickanimatorcontroller_p.h>
#include <QtCore/QCoreApplication>
@@ -50,6 +51,7 @@
#include <QtGui/QOffscreenSurface>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#include <QPlatformSurfaceEvent>
#include <QtQml/private/qqmlglobal_p.h>
@@ -59,23 +61,35 @@
#include <QtQuick/private/qsgrenderer_p.h>
#include <private/qquickprofiler_p.h>
+#include <private/qsgrhishadereffectnode_p.h>
+
#if QT_CONFIG(opengl)
-# include <QtGui/QOpenGLContext>
-# include <private/qsgdefaultrendercontext_p.h>
+#include <QtGui/QOpenGLContext>
#if QT_CONFIG(quick_shadereffect)
-# include <private/qquickopenglshadereffectnode_p.h>
+#include <private/qquickopenglshadereffectnode_p.h>
#endif
+#include <private/qsgdefaultrendercontext_p.h>
#endif
#ifdef Q_OS_WIN
-# include <QtCore/qt_windows.h>
+#include <QtCore/qt_windows.h>
#endif
QT_BEGIN_NAMESPACE
extern bool qsg_useConsistentTiming();
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-#if QT_CONFIG(opengl)
+
+// ### We do not yet support using Qt Quick with QRhi (and Vulkan, D3D
+// or Metal) in -no-opengl builds as of Qt 5.14. This is due to to the
+// widespread direct OpenGL usage all over the place in qsgdefault*
+// and the related classes. To be cleaned up in Qt 6 when the direct
+// GL code path is removed.
+
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+
+#define ENABLE_DEFAULT_BACKEND
+
/*
expectations for this manager to work:
- one opengl context to render multiple windows
@@ -88,17 +102,13 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk
#endif
+
QSGRenderLoop *QSGRenderLoop::s_instance = nullptr;
QSGRenderLoop::~QSGRenderLoop()
{
}
-QSurface::SurfaceType QSGRenderLoop::windowSurfaceType() const
-{
- return QSurface::OpenGLSurface;
-}
-
void QSGRenderLoop::cleanup()
{
if (!s_instance)
@@ -112,18 +122,36 @@ void QSGRenderLoop::cleanup()
}
delete s_instance;
s_instance = nullptr;
+
+#ifdef ENABLE_DEFAULT_BACKEND
+ QSGRhiSupport::instance()->cleanup();
+ QSGRhiProfileConnection::instance()->cleanup();
+#endif
+}
+
+QSurface::SurfaceType QSGRenderLoop::windowSurfaceType() const
+{
+#ifdef ENABLE_DEFAULT_BACKEND
+ return QSGRhiSupport::instance()->windowSurfaceType();
+#else
+ return QSurface::RasterSurface;
+#endif
}
-/*!
- * Non-threaded render loops immediately run the job if there is a context.
- */
void QSGRenderLoop::postJob(QQuickWindow *window, QRunnable *job)
{
Q_ASSERT(job);
-#if QT_CONFIG(opengl)
+#ifdef ENABLE_DEFAULT_BACKEND
Q_ASSERT(window);
- if (window->openglContext()) {
- window->openglContext()->makeCurrent(window);
+ if (!QSGRhiSupport::instance()->isRhiEnabled()) {
+ if (window->openglContext()) {
+ window->openglContext()->makeCurrent(window);
+ job->run();
+ }
+ } else {
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (cd->rhi)
+ cd->rhi->makeThreadLocalNativeContextCurrent();
job->run();
}
#else
@@ -132,7 +160,8 @@ void QSGRenderLoop::postJob(QQuickWindow *window, QRunnable *job)
#endif
delete job;
}
-#if QT_CONFIG(opengl)
+
+#ifdef ENABLE_DEFAULT_BACKEND
class QSGGuiThreadRenderLoop : public QSGRenderLoop
{
Q_OBJECT
@@ -160,6 +189,10 @@ public:
QSGContext *sceneGraphContext() const override;
QSGRenderContext *createRenderContext(QSGContext *) const override { return rc; }
+ void releaseSwapchain(QQuickWindow *window);
+
+ bool eventFilter(QObject *watched, QEvent *event) override;
+
struct WindowData {
bool updatePending : 1;
bool grabOnly : 1;
@@ -167,13 +200,16 @@ public:
QHash<QQuickWindow *, WindowData> m_windows;
- QOpenGLContext *gl;
+ QOpenGLContext *gl = nullptr;
+ QOffscreenSurface *offscreenSurface = nullptr;
+ QRhi *rhi = nullptr;
QSGContext *sg;
QSGRenderContext *rc;
QImage grabContent;
};
#endif
+
QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
@@ -183,28 +219,64 @@ QSGRenderLoop *QSGRenderLoop::instance()
const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
s_instance = QSGContext::createWindowManager();
-#if QT_CONFIG(opengl)
+#ifdef ENABLE_DEFAULT_BACKEND
if (!s_instance) {
+ QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
- enum RenderLoopType {
- BasicRenderLoop,
- ThreadedRenderLoop,
- WindowsRenderLoop
- };
-
- RenderLoopType loopType = BasicRenderLoop;
-
-#ifdef Q_OS_WIN
- // With desktop OpenGL (opengl32.dll), use threaded. Otherwise (ANGLE) use windows.
- if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
- && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSGRenderLoopType loopType;
+ if (rhiSupport->isRhiEnabled() && rhiSupport->rhiBackend() != QRhi::OpenGLES2) {
loopType = ThreadedRenderLoop;
- else
- loopType = WindowsRenderLoop;
+ } else {
+ loopType = BasicRenderLoop;
+#ifdef Q_OS_WIN
+ // With desktop OpenGL (opengl32.dll), use threaded. Otherwise (ANGLE) use windows.
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
+ && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ {
+ loopType = ThreadedRenderLoop;
+ } else {
+ loopType = WindowsRenderLoop;
+ }
#else
- if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
- loopType = ThreadedRenderLoop;
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ loopType = ThreadedRenderLoop;
+#endif
+ }
+
+ if (rhiSupport->isRhiEnabled()) {
+ // no 'windows' because that's not yet ported to the rhi
+ if (loopType == WindowsRenderLoop)
+ loopType = BasicRenderLoop;
+
+ switch (rhiSupport->rhiBackend()) {
+ case QRhi::Vulkan:
+#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
+ // ### to be investigated (Mesa/Gnome deadlocks on
+ // resize with threaded+Vulkan (but not threaded+GL))
+ loopType = BasicRenderLoop;
#endif
+ break;
+
+ case QRhi::D3D11:
+ // D3D11 is forced to 'basic' always for now. The threaded loop's model may
+ // not be suitable for DXGI due to the possibility of having the main
+ // thread blocked while issuing a Present. To be investigated.
+ loopType = BasicRenderLoop;
+ break;
+
+ case QRhi::Null:
+ loopType = BasicRenderLoop;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // The environment variables can always override. This is good
+ // because in some situations it makes perfect sense to try out a
+ // render loop that is otherwise disabled by default.
+
if (qmlNoThreadedRenderer())
loopType = BasicRenderLoop;
else if (qmlForceThreadedRenderer())
@@ -275,14 +347,15 @@ void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window,
if (!signalEmitted)
qFatal("%s", qPrintable(untranslatedMessage));
}
-#if QT_CONFIG(opengl)
+
+#ifdef ENABLE_DEFAULT_BACKEND
QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop()
- : gl(nullptr)
{
if (qsg_useConsistentTiming()) {
QUnifiedTimer::instance(true)->setConsistentTiming(true);
qCDebug(QSG_LOG_INFO, "using fixed animation steps");
}
+
sg = QSGContext::createDefaultContext();
rc = sg->createRenderContext();
}
@@ -318,38 +391,88 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool current = false;
- QScopedPointer<QOffscreenSurface> offscreenSurface;
if (gl) {
QSurface *surface = window;
// There may be no platform window if the window got closed.
- if (!window->handle()) {
- offscreenSurface.reset(new QOffscreenSurface);
- offscreenSurface->setFormat(gl->format());
- offscreenSurface->create();
- surface = offscreenSurface.data();
+ if (!window->handle())
+ surface = offscreenSurface;
+ if (rhi) {
+ rhi->makeThreadLocalNativeContextCurrent();
+ current = true;
+ } else {
+ current = gl->makeCurrent(surface);
}
- current = gl->makeCurrent(surface);
}
if (Q_UNLIKELY(!current))
qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context");
-#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
- if (current)
- QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+#if QT_CONFIG(quick_shadereffect)
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
+#if QT_CONFIG(opengl)
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+#endif
#endif
+ if (d->swapchain) {
+ if (window->handle()) {
+ // We get here when exiting via QCoreApplication::quit() instead of
+ // through QWindow::close().
+ releaseSwapchain(window);
+ } else {
+ qWarning("QSGGuiThreadRenderLoop cleanup with QQuickWindow %p swapchain %p still alive, this should not happen.",
+ window, d->swapchain);
+ }
+ }
+
d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
rc->invalidate();
+ d->rhi = nullptr;
+ delete rhi;
+ rhi = nullptr;
delete gl;
gl = nullptr;
+ delete offscreenSurface;
+ offscreenSurface = nullptr;
} else if (gl && window == gl->surface() && current) {
- gl->doneCurrent();
+ if (!rhi)
+ gl->doneCurrent();
}
delete d->animationController;
}
+void QSGGuiThreadRenderLoop::releaseSwapchain(QQuickWindow *window)
+{
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ delete wd->rpDescForSwapchain;
+ wd->rpDescForSwapchain = nullptr;
+ delete wd->swapchain;
+ wd->swapchain = nullptr;
+ delete wd->depthStencilForSwapchain;
+ wd->depthStencilForSwapchain = nullptr;
+ wd->hasActiveSwapchain = wd->hasRenderableSwapchain = wd->swapchainJustBecameRenderable = false;
+}
+
+bool QSGGuiThreadRenderLoop::eventFilter(QObject *watched, QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::PlatformSurface:
+ // this is the proper time to tear down the swapchain (while the native window and surface are still around)
+ if (static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+ QQuickWindow *w = qobject_cast<QQuickWindow *>(watched);
+ if (w) {
+ releaseSwapchain(w);
+ w->removeEventFilter(this);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::eventFilter(watched, event);
+}
+
void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
{
if (!m_windows.contains(window))
@@ -364,8 +487,36 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
return;
bool current = false;
-
- if (!gl) {
+ QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
+ int rhiSampleCount = 1;
+ const bool enableRhi = rhiSupport->isRhiEnabled();
+
+ if (enableRhi && !rhi) {
+ offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window);
+ rhi = rhiSupport->createRhi(window, offscreenSurface);
+ if (rhi) {
+ if (rhiSupport->isProfilingRequested())
+ QSGRhiProfileConnection::instance()->initialize(rhi);
+
+ current = true;
+ rhi->makeThreadLocalNativeContextCurrent();
+
+ // The sample count cannot vary between windows as we use the same
+ // rendercontext for all of them. Decide it here and now.
+ rhiSampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, rhi);
+
+ cd->rhi = rhi; // set this early in case something hooked up to rc initialized() accesses it
+
+ QSGDefaultRenderContext::InitParams rcParams;
+ rcParams.rhi = rhi;
+ rcParams.sampleCount = rhiSampleCount;
+ rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
+ rcParams.maybeSurface = window;
+ cd->context->initialize(&rcParams);
+ } else {
+ handleContextCreationFailure(window, false);
+ }
+ } else if (!enableRhi && !gl) {
gl = new QOpenGLContext();
gl->setFormat(window->requestedFormat());
gl->setScreen(window->screen());
@@ -377,15 +528,57 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
gl = nullptr;
handleContextCreationFailure(window, isEs);
} else {
+ if (!offscreenSurface) {
+ offscreenSurface = new QOffscreenSurface;
+ offscreenSurface->setFormat(gl->format());
+ offscreenSurface->create();
+ }
cd->fireOpenGLContextCreated(gl);
current = gl->makeCurrent(window);
}
if (current) {
- auto openglRenderContext = static_cast<QSGDefaultRenderContext *>(cd->context);
- openglRenderContext->initialize(gl);
+ QSGDefaultRenderContext::InitParams rcParams;
+ rcParams.sampleCount = qMax(1, gl->format().samples());
+ rcParams.openGLContext = gl;
+ rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
+ rcParams.maybeSurface = window;
+ cd->context->initialize(&rcParams);
}
} else {
- current = gl->makeCurrent(window);
+ if (rhi) {
+ current = true;
+ // 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 = gl->makeCurrent(window);
+ }
+ }
+
+ if (enableRhi && rhi && !cd->swapchain) {
+ // if it's not the first window then the rhi is not yet stored to
+ // QQuickWindowPrivate, do it now
+ cd->rhi = rhi;
+
+ QRhiSwapChain::Flags flags = QRhiSwapChain::UsedAsTransferSource; // may be used in a grab
+
+ cd->swapchain = rhi->newSwapChain();
+ cd->depthStencilForSwapchain = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
+ QSize(),
+ rhiSampleCount,
+ QRhiRenderBuffer::UsedWithSwapChainOnly);
+ cd->swapchain->setWindow(window);
+ cd->swapchain->setDepthStencil(cd->depthStencilForSwapchain);
+ qDebug("MSAA sample count for the swapchain is %d", rhiSampleCount);
+ cd->swapchain->setSampleCount(rhiSampleCount);
+ cd->swapchain->setFlags(flags);
+ cd->rpDescForSwapchain = cd->swapchain->newCompatibleRenderPassDescriptor();
+ cd->swapchain->setRenderPassDescriptor(cd->rpDescForSwapchain);
+
+ window->installEventFilter(this);
}
bool lastDirtyWindow = true;
@@ -407,6 +600,17 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!m_windows.contains(window))
return;
}
+
+ QSize effectiveOutputSize; // always prefer what the surface tells us, not the QWindow
+ if (cd->swapchain) {
+ effectiveOutputSize = cd->swapchain->surfacePixelSize();
+ // An update request could still be delivered right before we get an
+ // unexpose. With Vulkan on Windows for example attempting to render
+ // leads to failures at this stage since the surface size is already 0.
+ if (effectiveOutputSize.isEmpty())
+ return;
+ }
+
QElapsedTimer renderTimer;
qint64 renderTime = 0, syncTime = 0, polishTime = 0;
bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
@@ -424,6 +628,41 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
emit window->afterAnimating();
+ // Begin the frame before syncing -> sync is where we may invoke
+ // updatePaintNode() on the items and they may want to do resource updates.
+ // Also relevant for applications that connect to the before/afterSynchronizing
+ // signals and want to do graphics stuff already there.
+ if (cd->swapchain) {
+ Q_ASSERT(!effectiveOutputSize.isEmpty());
+ const QSize previousOutputSize = cd->swapchain->currentPixelSize();
+ if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) {
+ if (cd->swapchainJustBecameRenderable)
+ qDebug("just became exposed");
+ cd->swapchainJustBecameRenderable = false;
+ cd->depthStencilForSwapchain->setPixelSize(effectiveOutputSize);
+
+ cd->depthStencilForSwapchain->build();
+ cd->hasActiveSwapchain = cd->swapchain->buildOrResize();
+
+ cd->hasRenderableSwapchain = cd->hasActiveSwapchain;
+ if (!cd->hasActiveSwapchain)
+ qWarning("Failed to build or resize swapchain");
+ else
+ qDebug() << "rhi swapchain size" << effectiveOutputSize;
+ }
+
+ Q_ASSERT(rhi == cd->rhi);
+ QRhi::FrameOpResult frameResult = rhi->beginFrame(cd->swapchain);
+ if (frameResult != QRhi::FrameOpSuccess) {
+ if (frameResult == QRhi::FrameOpDeviceLost)
+ qWarning("Device lost");
+ 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
+ return;
+ }
+ }
+
cd->syncSceneGraph();
if (lastDirtyWindow)
rc->endSync();
@@ -433,7 +672,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
- cd->renderSceneGraph(window->size());
+ cd->renderSceneGraph(window->size(), effectiveOutputSize);
if (profileFrames)
renderTime = renderTimer.nsecsElapsed();
@@ -441,17 +680,27 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
QQuickProfiler::SceneGraphRenderLoopRender);
if (data.grabOnly) {
- bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
- grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
+ const bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
+ if (cd->swapchain)
+ grabContent = rhiSupport->grabAndBlockInCurrentFrame(rhi, cd->swapchain);
+ else
+ grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
grabContent.setDevicePixelRatio(window->effectiveDevicePixelRatio());
data.grabOnly = false;
}
- if (alsoSwap && window->isVisible()) {
+ const bool needsPresent = alsoSwap && window->isVisible();
+ if (cd->swapchain) {
+ QRhi::EndFrameFlags flags = 0;
+ if (!needsPresent)
+ flags |= QRhi::SkipPresent;
+ rhi->endFrame(cd->swapchain, flags);
+ } else if (needsPresent) {
if (!cd->customRenderStage || !cd->customRenderStage->swap())
gl->swapBuffers(window);
- cd->fireFrameSwapped();
}
+ if (needsPresent)
+ cd->fireFrameSwapped();
qint64 swapTime = 0;
if (profileFrames)
@@ -472,6 +721,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
lastFrameTime = QTime::currentTime();
}
+ QSGRhiProfileConnection::instance()->send(rhi);
+
// Might have been set during syncSceneGraph()
if (data.updatePending)
maybeUpdate(window);
@@ -479,7 +730,26 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
void QSGGuiThreadRenderLoop::exposureChanged(QQuickWindow *window)
{
- if (window->isExposed()) {
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+
+ // This is tricker than used to be. We want to detect having an empty
+ // surface size (which may be the case even when window->size() is
+ // non-empty, on some platforms with some graphics APIs!) as well as the
+ // case when the window just became "newly exposed" (e.g. after a
+ // minimize-restore on Windows, or when switching between fully obscured -
+ // not fully obscured on macOS)
+
+ if (!window->isExposed() || (wd->hasActiveSwapchain && wd->swapchain->surfacePixelSize().isEmpty()))
+ wd->hasRenderableSwapchain = false;
+
+ if (window->isExposed() && !wd->hasRenderableSwapchain && wd->hasActiveSwapchain
+ && !wd->swapchain->surfacePixelSize().isEmpty())
+ {
+ wd->hasRenderableSwapchain = true;
+ wd->swapchainJustBecameRenderable = true;
+ }
+
+ if (window->isExposed() && (!rhi || !wd->hasActiveSwapchain || wd->hasRenderableSwapchain)) {
m_windows[window].updatePending = true;
renderWindow(window);
}
@@ -527,7 +797,7 @@ void QSGGuiThreadRenderLoop::handleUpdateRequest(QQuickWindow *window)
renderWindow(window);
}
-#endif
+#endif // ENABLE_DEFAULT_BACKEND
#include "qsgrenderloop.moc"
#include "moc_qsgrenderloop_p.cpp"