176QSGRenderLoop *QSGRenderLoop::instance()
180 QSGRhiSupport::checkEnvQSgInfo();
182 s_instance = QSGContext::createWindowManager();
185 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
187 QSGRenderLoopType loopType;
188 if (rhiSupport->rhiBackend() != QRhi::OpenGLES2) {
189 loopType = ThreadedRenderLoop;
191 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
192 loopType = ThreadedRenderLoop;
194 loopType = BasicRenderLoop;
197 switch (rhiSupport->rhiBackend()) {
199 loopType = BasicRenderLoop;
220 if (qmlNoThreadedRenderer())
221 loopType = BasicRenderLoop;
222 else if (qmlForceThreadedRenderer())
223 loopType = ThreadedRenderLoop;
225 if (Q_UNLIKELY(qEnvironmentVariableIsSet(
"QSG_RENDER_LOOP"))) {
226 const QByteArray loopName = qgetenv(
"QSG_RENDER_LOOP");
227 if (loopName ==
"windows") {
228 qWarning(
"The 'windows' render loop is no longer supported. Using 'basic' instead.");
229 loopType = BasicRenderLoop;
230 }
else if (loopName ==
"basic") {
231 loopType = BasicRenderLoop;
232 }
else if (loopName ==
"threaded") {
233 loopType = ThreadedRenderLoop;
239 case ThreadedRenderLoop:
240 qCDebug(QSG_LOG_INFO,
"threaded render loop");
241 s_instance =
new QSGThreadedRenderLoop();
245 qCDebug(QSG_LOG_INFO,
"basic render loop");
246 s_instance =
new QSGGuiThreadRenderLoop();
251 qAddPostRoutine(QSGRenderLoop::cleanup);
263void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window)
268 static QSet<QQuickWindow *> recurseGuard;
269 if (recurseGuard.contains(window))
272 recurseGuard.insert(window);
274 QString translatedMessage;
275 QString untranslatedMessage;
276 QQuickWindowPrivate::rhiCreationFailureMessage(QSGRhiSupport::instance()->rhiBackendName(),
278 &untranslatedMessage);
282 const bool signalEmitted =
283 QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
286 if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
287 MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
288 (LPCTSTR)(QCoreApplication::applicationName().utf16()),
289 MB_OK | MB_ICONERROR);
293 qFatal(
"%s", qPrintable(untranslatedMessage));
295 recurseGuard.remove(window);
454 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
455 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
456 bool ok = data
.rhi !=
nullptr;
466 if (!offscreenSurface)
467 offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window);
470 QSGRhiSupport::RhiCreateResult rhiResult = rhiSupport->createRhi(window, offscreenSurface, forcePreferSwRenderer);
471 data
.rhi = rhiResult.rhi;
480 data
.rhi->makeThreadLocalNativeContextCurrent();
484 data.sampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, data.rhi);
488 QSGDefaultRenderContext::InitParams rcParams;
489 rcParams.rhi = data
.rhi;
491 rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
492 rcParams.maybeSurface = window;
493 cd->context->initialize(&rcParams);
497 handleContextCreationFailure(window);
503 if (data
.rhi && !cd->swapchain) {
511 rhiSupport->prepareWindowForRhi(window);
513 QRhiSwapChain::Flags flags = QRhiSwapChain::UsedAsTransferSource;
514 const QSurfaceFormat requestedFormat = window->requestedFormat();
520 const bool alpha = requestedFormat.alphaBufferSize() > 0;
522 flags |= QRhiSwapChain::SurfaceHasPreMulAlpha;
527 if (requestedFormat.swapInterval() == 0) {
528 qCDebug(QSG_LOG_INFO,
"Swap interval is 0, attempting to disable vsync when presenting.");
529 flags |= QRhiSwapChain::NoVSync;
532 cd->swapchain = data
.rhi->newSwapChain();
533 static bool depthBufferEnabled = qEnvironmentVariableIsEmpty(
"QSG_NO_DEPTH_BUFFER");
534 if (depthBufferEnabled) {
535 cd->depthStencilForSwapchain = data
.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
538 QRhiRenderBuffer::UsedWithSwapChainOnly);
539 cd->swapchain->setDepthStencil(cd->depthStencilForSwapchain);
541 cd->swapchain->setWindow(window);
542 rhiSupport->applySwapChainFormat(cd->swapchain, window);
543 qCDebug(QSG_LOG_INFO,
"MSAA sample count for the swapchain is %d. Alpha channel requested = %s",
546 cd->swapchain->setFlags(flags);
547 cd->rpDescForSwapchain = cd->swapchain->newCompatibleRenderPassDescriptor();
548 cd->swapchain->setRenderPassDescriptor(cd->rpDescForSwapchain);
550 window->installEventFilter(
this);
554 QSGRenderContext *rc = cd->context;
555 pendingRenderContexts.remove(rc);
558 qWarning(
"No QSGRenderContext for window %p, this should not happen", window);
566 auto winDataIt = m_windows.find(window);
567 if (winDataIt == m_windows.end())
574 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
575 if (!cd->isRenderable())
578 if (!cd->updatesEnabled)
584 cd->deliveryAgentPrivate()->flushFrameSynchronousEvents(window);
586 if (!m_windows.contains(window))
589 QSize effectiveOutputSize;
591 effectiveOutputSize = cd->swapchain->surfacePixelSize();
595 if (effectiveOutputSize.isEmpty())
599 Q_TRACE_SCOPE(QSG_renderWindow);
600 QElapsedTimer renderTimer;
601 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
602 const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
605 Q_TRACE(QSG_polishItems_entry);
606 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
613 polishTime = renderTimer.nsecsElapsed();
615 Q_TRACE(QSG_polishItems_exit);
616 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
617 QQuickProfiler::SceneGraphRenderLoopFrame,
618 QQuickProfiler::SceneGraphPolishPolish);
619 Q_TRACE(QSG_sync_entry);
621 emit window->afterAnimating();
628 Q_ASSERT(!effectiveOutputSize.isEmpty());
629 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
630 const QSize previousOutputSize = cd->swapchain->currentPixelSize();
631 if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) {
632 if (cd->swapchainJustBecameRenderable)
633 qCDebug(QSG_LOG_RENDERLOOP,
"just became exposed");
635 cd->hasActiveSwapchain = cd->swapchain->createOrResize();
636 if (!cd->hasActiveSwapchain) {
637 if (data
.rhi->isDeviceLost()) {
640 }
else if (previousOutputSize.isEmpty() && !swRastFallbackDueToSwapchainFailure && rhiSupport->attemptReinitWithSwRastUponFail()) {
641 qWarning(
"Failed to create swapchain."
642 " Retrying by requesting a software rasterizer, if applicable for the 3D API implementation.");
649 cd->swapchainJustBecameRenderable =
false;
650 cd->hasRenderableSwapchain = cd->hasActiveSwapchain;
652 if (cd->hasActiveSwapchain) {
656 effectiveOutputSize = cd->swapchain->currentPixelSize();
657 qCDebug(QSG_LOG_RENDERLOOP) <<
"rhi swapchain size" << effectiveOutputSize;
659 qWarning(
"Failed to build or resize swapchain");
663 emit window->beforeFrameBegin();
665 Q_ASSERT(data
.rhi == cd->rhi);
666 QRhi::FrameOpResult frameResult = data
.rhi->beginFrame(cd->swapchain);
667 if (frameResult != QRhi::FrameOpSuccess) {
668 if (frameResult == QRhi::FrameOpDeviceLost)
670 else if (frameResult == QRhi::FrameOpError)
671 qWarning(
"Failed to start frame");
673 emit window->afterFrameEnd();
682 data
.rhi->makeThreadLocalNativeContextCurrent();
684 cd->syncSceneGraph();
688 syncTime = renderTimer.nsecsElapsed();
690 Q_TRACE(QSG_sync_exit);
691 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
692 QQuickProfiler::SceneGraphRenderLoopSync);
693 Q_TRACE(QSG_render_entry);
695 cd->renderSceneGraph();
698 renderTime = renderTimer.nsecsElapsed();
699 Q_TRACE(QSG_render_exit);
700 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
701 QQuickProfiler::SceneGraphRenderLoopRender);
702 Q_TRACE(QSG_swap_entry);
704 const bool needsPresent = alsoSwap && window->isVisible();
705 double lastCompletedGpuTime = 0;
707 QRhi::EndFrameFlags flags;
709 flags |= QRhi::SkipPresent;
710 QRhi::FrameOpResult frameResult = data
.rhi->endFrame(cd->swapchain, flags);
711 if (frameResult != QRhi::FrameOpSuccess) {
712 if (frameResult == QRhi::FrameOpDeviceLost)
714 else if (frameResult == QRhi::FrameOpError)
715 qWarning(
"Failed to end frame");
717 lastCompletedGpuTime = cd->swapchain->currentFrameCommandBuffer()->lastCompletedGpuTime();
721 cd->fireFrameSwapped();
723 emit window->afterFrameEnd();
727 swapTime = renderTimer.nsecsElapsed();
729 Q_TRACE(QSG_swap_exit);
730 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
731 QQuickProfiler::SceneGraphRenderLoopSwap);
734 qCDebug(QSG_LOG_TIME_RENDERLOOP,
735 "[window %p][gui thread] syncAndRender: frame rendered in %dms, polish=%d, sync=%d, render=%d, swap=%d, perWindowFrameDelta=%d",
737 int(swapTime / 1000000),
738 int(polishTime / 1000000),
739 int((syncTime - polishTime) / 1000000),
740 int((renderTime - syncTime) / 1000000),
741 int((swapTime - renderTime) / 1000000),
742 int(data.timeBetweenRenders.restart()));
743 if (!qFuzzyIsNull(lastCompletedGpuTime) && cd->graphicsConfig.timestampsEnabled()) {
744 qCDebug(QSG_LOG_TIME_RENDERLOOP,
"[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms",
746 lastCompletedGpuTime * 1000.0);