177QSGRenderLoop *QSGRenderLoop::instance()
181 QSGRhiSupport::checkEnvQSgInfo();
183 s_instance = QSGContext::createWindowManager();
186 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
188 QSGRenderLoopType loopType;
189 if (rhiSupport->rhiBackend() != QRhi::OpenGLES2) {
190 loopType = ThreadedRenderLoop;
192 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
193 loopType = ThreadedRenderLoop;
195 loopType = BasicRenderLoop;
198 switch (rhiSupport->rhiBackend()) {
200 loopType = BasicRenderLoop;
221 if (qmlNoThreadedRenderer())
222 loopType = BasicRenderLoop;
223 else if (qmlForceThreadedRenderer())
224 loopType = ThreadedRenderLoop;
226 if (Q_UNLIKELY(qEnvironmentVariableIsSet(
"QSG_RENDER_LOOP"))) {
227 const QByteArray loopName = qgetenv(
"QSG_RENDER_LOOP");
228 if (loopName ==
"windows") {
229 qWarning(
"The 'windows' render loop is no longer supported. Using 'basic' instead.");
230 loopType = BasicRenderLoop;
231 }
else if (loopName ==
"basic") {
232 loopType = BasicRenderLoop;
233 }
else if (loopName ==
"threaded") {
234 loopType = ThreadedRenderLoop;
240 case ThreadedRenderLoop:
241 qCDebug(QSG_LOG_INFO,
"threaded render loop");
242 s_instance =
new QSGThreadedRenderLoop();
246 qCDebug(QSG_LOG_INFO,
"basic render loop");
247 s_instance =
new QSGGuiThreadRenderLoop();
252 qAddPostRoutine(QSGRenderLoop::cleanup);
264void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window)
269 static QSet<QQuickWindow *> recurseGuard;
270 if (recurseGuard.contains(window))
273 recurseGuard.insert(window);
275 QString translatedMessage;
276 QString untranslatedMessage;
277 QQuickWindowPrivate::rhiCreationFailureMessage(QSGRhiSupport::instance()->rhiBackendName(),
279 &untranslatedMessage);
283 const bool signalEmitted =
284 QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
287 if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
288 MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
289 (LPCTSTR)(QCoreApplication::applicationName().utf16()),
290 MB_OK | MB_ICONERROR);
294 qFatal(
"%s", qPrintable(untranslatedMessage));
296 recurseGuard.remove(window);
459 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
460 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
461 bool ok = data
.rhi !=
nullptr;
471 if (!offscreenSurface)
472 offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window);
475 QSGRhiSupport::RhiCreateResult rhiResult = rhiSupport->createRhi(window, offscreenSurface, forcePreferSwRenderer);
476 data
.rhi = rhiResult.rhi;
485 data
.rhi->makeThreadLocalNativeContextCurrent();
489 data.sampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, data.rhi);
493 QSGDefaultRenderContext::InitParams rcParams;
494 rcParams.rhi = data
.rhi;
496 rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
497 rcParams.maybeSurface = window;
498 cd->context->initialize(&rcParams);
502 handleContextCreationFailure(window);
508 if (data
.rhi && !cd->swapchain) {
516 rhiSupport->prepareWindowForRhi(window);
518 QRhiSwapChain::Flags flags = QRhiSwapChain::UsedAsTransferSource;
519 const QSurfaceFormat requestedFormat = window->requestedFormat();
525 const bool alpha = requestedFormat.alphaBufferSize() > 0;
527 flags |= QRhiSwapChain::SurfaceHasPreMulAlpha;
532 if (requestedFormat.swapInterval() == 0) {
533 qCDebug(QSG_LOG_INFO,
"Swap interval is 0, attempting to disable vsync when presenting.");
534 flags |= QRhiSwapChain::NoVSync;
537 cd->swapchain = data
.rhi->newSwapChain();
538 static bool depthBufferEnabled = qEnvironmentVariableIsEmpty(
"QSG_NO_DEPTH_BUFFER");
539 if (depthBufferEnabled) {
540 cd->depthStencilForSwapchain = data
.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
543 QRhiRenderBuffer::UsedWithSwapChainOnly
544 | QSGRhiSupport::depthStencilBufferFlags());
545 cd->swapchain->setDepthStencil(cd->depthStencilForSwapchain);
547 cd->swapchain->setWindow(window);
548 rhiSupport->applySwapChainFormat(cd->swapchain, window);
549 qCDebug(QSG_LOG_INFO,
"MSAA sample count for the swapchain is %d. Alpha channel requested = %s",
552 cd->swapchain->setFlags(flags);
553 cd->rpDescForSwapchain = cd->swapchain->newCompatibleRenderPassDescriptor();
554 cd->swapchain->setRenderPassDescriptor(cd->rpDescForSwapchain);
556 window->installEventFilter(
this);
560 QSGRenderContext *rc = cd->context;
561 pendingRenderContexts.remove(rc);
564 qWarning(
"No QSGRenderContext for window %p, this should not happen", window);
572 auto winDataIt = m_windows.find(window);
573 if (winDataIt == m_windows.end())
580 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
581 if (!cd->isRenderable())
584 if (!cd->updatesEnabled)
590 cd->deliveryAgentPrivate()->flushFrameSynchronousEvents(window);
592 if (!m_windows.contains(window))
595 QSize effectiveOutputSize;
597 effectiveOutputSize = cd->swapchain->surfacePixelSize();
601 if (effectiveOutputSize.isEmpty())
605 Q_TRACE_SCOPE(QSG_renderWindow);
606 QElapsedTimer renderTimer;
607 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
608 const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
611 Q_TRACE(QSG_polishItems_entry);
612 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
619 polishTime = renderTimer.nsecsElapsed();
621 Q_TRACE(QSG_polishItems_exit);
622 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
623 QQuickProfiler::SceneGraphRenderLoopFrame,
624 QQuickProfiler::SceneGraphPolishPolish);
625 Q_TRACE(QSG_sync_entry);
627 emit window->afterAnimating();
634 Q_ASSERT(!effectiveOutputSize.isEmpty());
635 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
636 const QSize previousOutputSize = cd->swapchain->currentPixelSize();
637 if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) {
638 if (cd->swapchainJustBecameRenderable)
639 qCDebug(QSG_LOG_RENDERLOOP,
"just became exposed");
641 cd->hasActiveSwapchain = cd->swapchain->createOrResize();
642 if (!cd->hasActiveSwapchain) {
643 if (data
.rhi->isDeviceLost()) {
646 }
else if (previousOutputSize.isEmpty() && !swRastFallbackDueToSwapchainFailure && rhiSupport->attemptReinitWithSwRastUponFail()) {
647 qWarning(
"Failed to create swapchain."
648 " Retrying by requesting a software rasterizer, if applicable for the 3D API implementation.");
655 cd->swapchainJustBecameRenderable =
false;
656 cd->hasRenderableSwapchain = cd->hasActiveSwapchain;
658 if (cd->hasActiveSwapchain) {
662 effectiveOutputSize = cd->swapchain->currentPixelSize();
663 qCDebug(QSG_LOG_RENDERLOOP) <<
"rhi swapchain size" << effectiveOutputSize;
665 qWarning(
"Failed to build or resize swapchain");
669 emit window->beforeFrameBegin();
671 Q_ASSERT(data
.rhi == cd->rhi);
672 QRhi::FrameOpResult frameResult = data
.rhi->beginFrame(cd->swapchain);
673 if (frameResult != QRhi::FrameOpSuccess) {
674 if (frameResult == QRhi::FrameOpDeviceLost)
676 else if (frameResult == QRhi::FrameOpError)
677 qWarning(
"Failed to start frame");
679 emit window->afterFrameEnd();
688 data
.rhi->makeThreadLocalNativeContextCurrent();
690 cd->syncSceneGraph();
694 syncTime = renderTimer.nsecsElapsed();
696 Q_TRACE(QSG_sync_exit);
697 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
698 QQuickProfiler::SceneGraphRenderLoopSync);
699 Q_TRACE(QSG_render_entry);
701 cd->renderSceneGraph();
704 renderTime = renderTimer.nsecsElapsed();
705 Q_TRACE(QSG_render_exit);
706 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
707 QQuickProfiler::SceneGraphRenderLoopRender);
708 Q_TRACE(QSG_swap_entry);
710 const bool needsPresent = alsoSwap && window->isVisible();
711 double lastCompletedGpuTime = 0;
713 QRhi::EndFrameFlags flags;
715 flags |= QRhi::SkipPresent;
716 QRhi::FrameOpResult frameResult = data
.rhi->endFrame(cd->swapchain, flags);
717 if (frameResult != QRhi::FrameOpSuccess) {
718 if (frameResult == QRhi::FrameOpDeviceLost)
720 else if (frameResult == QRhi::FrameOpError)
721 qWarning(
"Failed to end frame");
723 lastCompletedGpuTime = cd->swapchain->currentFrameCommandBuffer()->lastCompletedGpuTime();
727 cd->fireFrameSwapped();
729 emit window->afterFrameEnd();
733 swapTime = renderTimer.nsecsElapsed();
735 Q_TRACE(QSG_swap_exit);
736 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
737 QQuickProfiler::SceneGraphRenderLoopSwap);
740 qCDebug(QSG_LOG_TIME_RENDERLOOP,
741 "[window %p][gui thread] syncAndRender: frame rendered in %dms, polish=%d, sync=%d, render=%d, swap=%d, perWindowFrameDelta=%d",
743 int(swapTime / 1000000),
744 int(polishTime / 1000000),
745 int((syncTime - polishTime) / 1000000),
746 int((renderTime - syncTime) / 1000000),
747 int((swapTime - renderTime) / 1000000),
748 int(data.timeBetweenRenders.restart()));
749 if (!qFuzzyIsNull(lastCompletedGpuTime) && cd->graphicsConfig.timestampsEnabled()) {
750 qCDebug(QSG_LOG_TIME_RENDERLOOP,
"[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms",
752 lastCompletedGpuTime * 1000.0);