175QSGRenderLoop *QSGRenderLoop::instance()
179 QSGRhiSupport::checkEnvQSgInfo();
181 s_instance = QSGContext::createWindowManager();
184 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
186 QSGRenderLoopType loopType;
187 if (rhiSupport->rhiBackend() != QRhi::OpenGLES2) {
188 loopType = ThreadedRenderLoop;
190 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
191 loopType = ThreadedRenderLoop;
193 loopType = BasicRenderLoop;
196 switch (rhiSupport->rhiBackend()) {
198 loopType = BasicRenderLoop;
219 if (qmlNoThreadedRenderer())
220 loopType = BasicRenderLoop;
221 else if (qmlForceThreadedRenderer())
222 loopType = ThreadedRenderLoop;
224 if (Q_UNLIKELY(qEnvironmentVariableIsSet(
"QSG_RENDER_LOOP"))) {
225 const QByteArray loopName = qgetenv(
"QSG_RENDER_LOOP");
226 if (loopName ==
"windows") {
227 qWarning(
"The 'windows' render loop is no longer supported. Using 'basic' instead.");
228 loopType = BasicRenderLoop;
229 }
else if (loopName ==
"basic") {
230 loopType = BasicRenderLoop;
231 }
else if (loopName ==
"threaded") {
232 loopType = ThreadedRenderLoop;
238 case ThreadedRenderLoop:
239 qCDebug(QSG_LOG_INFO,
"threaded render loop");
240 s_instance =
new QSGThreadedRenderLoop();
244 qCDebug(QSG_LOG_INFO,
"basic render loop");
245 s_instance =
new QSGGuiThreadRenderLoop();
250 qAddPostRoutine(QSGRenderLoop::cleanup);
262void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window)
267 static QSet<QQuickWindow *> recurseGuard;
268 if (recurseGuard.contains(window))
271 recurseGuard.insert(window);
273 QString translatedMessage;
274 QString untranslatedMessage;
275 QQuickWindowPrivate::rhiCreationFailureMessage(QSGRhiSupport::instance()->rhiBackendName(),
277 &untranslatedMessage);
281 const bool signalEmitted =
282 QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
285 if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
286 MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
287 (LPCTSTR)(QCoreApplication::applicationName().utf16()),
288 MB_OK | MB_ICONERROR);
292 qFatal(
"%s", qPrintable(untranslatedMessage));
294 recurseGuard.remove(window);
453 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
454 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
455 bool ok = data
.rhi !=
nullptr;
465 if (!offscreenSurface)
466 offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window);
469 QSGRhiSupport::RhiCreateResult rhiResult = rhiSupport->createRhi(window, offscreenSurface, forcePreferSwRenderer);
470 data
.rhi = rhiResult.rhi;
479 data
.rhi->makeThreadLocalNativeContextCurrent();
483 data.sampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, data.rhi);
487 QSGDefaultRenderContext::InitParams rcParams;
488 rcParams.rhi = data
.rhi;
490 rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
491 rcParams.maybeSurface = window;
492 cd->context->initialize(&rcParams);
496 handleContextCreationFailure(window);
502 if (data
.rhi && !cd->swapchain) {
510 rhiSupport->prepareWindowForRhi(window);
512 QRhiSwapChain::Flags flags = QRhiSwapChain::UsedAsTransferSource;
513 const QSurfaceFormat requestedFormat = window->requestedFormat();
519 const bool alpha = requestedFormat.alphaBufferSize() > 0;
521 flags |= QRhiSwapChain::SurfaceHasPreMulAlpha;
526 if (requestedFormat.swapInterval() == 0) {
527 qCDebug(QSG_LOG_INFO,
"Swap interval is 0, attempting to disable vsync when presenting.");
528 flags |= QRhiSwapChain::NoVSync;
531 cd->swapchain = data
.rhi->newSwapChain();
532 static bool depthBufferEnabled = qEnvironmentVariableIsEmpty(
"QSG_NO_DEPTH_BUFFER");
533 if (depthBufferEnabled) {
534 cd->depthStencilForSwapchain = data.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
537 QRhiRenderBuffer::UsedWithSwapChainOnly);
538 cd->swapchain->setDepthStencil(cd->depthStencilForSwapchain);
540 cd->swapchain->setWindow(window);
541 rhiSupport->applySwapChainFormat(cd->swapchain, window);
542 qCDebug(QSG_LOG_INFO,
"MSAA sample count for the swapchain is %d. Alpha channel requested = %s",
543 data.sampleCount, alpha ?
"yes" :
"no");
545 cd->swapchain->setFlags(flags);
546 cd->rpDescForSwapchain = cd->swapchain->newCompatibleRenderPassDescriptor();
547 cd->swapchain->setRenderPassDescriptor(cd->rpDescForSwapchain);
549 window->installEventFilter(
this);
553 QSGRenderContext *rc = cd->context;
554 pendingRenderContexts.remove(rc);
557 qWarning(
"No QSGRenderContext for window %p, this should not happen", window);
565 auto winDataIt = m_windows.find(window);
566 if (winDataIt == m_windows.end())
573 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
574 if (!cd->isRenderable())
577 if (!cd->updatesEnabled)
583 cd->deliveryAgentPrivate()->flushFrameSynchronousEvents(window);
585 if (!m_windows.contains(window))
588 QSize effectiveOutputSize;
590 effectiveOutputSize = cd->swapchain->surfacePixelSize();
594 if (effectiveOutputSize.isEmpty())
598 Q_TRACE_SCOPE(QSG_renderWindow);
599 QElapsedTimer renderTimer;
600 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
601 const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
604 Q_TRACE(QSG_polishItems_entry);
605 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
612 polishTime = renderTimer.nsecsElapsed();
614 Q_TRACE(QSG_polishItems_exit);
615 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
616 QQuickProfiler::SceneGraphRenderLoopFrame,
617 QQuickProfiler::SceneGraphPolishPolish);
618 Q_TRACE(QSG_sync_entry);
620 emit window->afterAnimating();
627 Q_ASSERT(!effectiveOutputSize.isEmpty());
628 QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
629 const QSize previousOutputSize = cd->swapchain->currentPixelSize();
630 if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) {
631 if (cd->swapchainJustBecameRenderable)
632 qCDebug(QSG_LOG_RENDERLOOP,
"just became exposed");
634 cd->hasActiveSwapchain = cd->swapchain->createOrResize();
635 if (!cd->hasActiveSwapchain) {
636 if (data
.rhi->isDeviceLost()) {
639 }
else if (previousOutputSize.isEmpty() && !swRastFallbackDueToSwapchainFailure && rhiSupport->attemptReinitWithSwRastUponFail()) {
640 qWarning(
"Failed to create swapchain."
641 " Retrying by requesting a software rasterizer, if applicable for the 3D API implementation.");
648 cd->swapchainJustBecameRenderable =
false;
649 cd->hasRenderableSwapchain = cd->hasActiveSwapchain;
651 if (cd->hasActiveSwapchain) {
655 effectiveOutputSize = cd->swapchain->currentPixelSize();
656 qCDebug(QSG_LOG_RENDERLOOP) <<
"rhi swapchain size" << effectiveOutputSize;
658 qWarning(
"Failed to build or resize swapchain");
662 emit window->beforeFrameBegin();
664 Q_ASSERT(data
.rhi == cd->rhi);
665 QRhi::FrameOpResult frameResult = data
.rhi->beginFrame(cd->swapchain);
666 if (frameResult != QRhi::FrameOpSuccess) {
667 if (frameResult == QRhi::FrameOpDeviceLost)
669 else if (frameResult == QRhi::FrameOpError)
670 qWarning(
"Failed to start frame");
672 emit window->afterFrameEnd();
681 data
.rhi->makeThreadLocalNativeContextCurrent();
683 cd->syncSceneGraph();
687 syncTime = renderTimer.nsecsElapsed();
689 Q_TRACE(QSG_sync_exit);
690 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
691 QQuickProfiler::SceneGraphRenderLoopSync);
692 Q_TRACE(QSG_render_entry);
694 cd->renderSceneGraph();
697 renderTime = renderTimer.nsecsElapsed();
698 Q_TRACE(QSG_render_exit);
699 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
700 QQuickProfiler::SceneGraphRenderLoopRender);
701 Q_TRACE(QSG_swap_entry);
703 const bool needsPresent = alsoSwap && window->isVisible();
704 double lastCompletedGpuTime = 0;
706 QRhi::EndFrameFlags flags;
708 flags |= QRhi::SkipPresent;
709 QRhi::FrameOpResult frameResult = data
.rhi->endFrame(cd->swapchain, flags);
710 if (frameResult != QRhi::FrameOpSuccess) {
711 if (frameResult == QRhi::FrameOpDeviceLost)
713 else if (frameResult == QRhi::FrameOpError)
714 qWarning(
"Failed to end frame");
716 lastCompletedGpuTime = cd->swapchain->currentFrameCommandBuffer()->lastCompletedGpuTime();
720 cd->fireFrameSwapped();
722 emit window->afterFrameEnd();
726 swapTime = renderTimer.nsecsElapsed();
728 Q_TRACE(QSG_swap_exit);
729 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
730 QQuickProfiler::SceneGraphRenderLoopSwap);
733 qCDebug(QSG_LOG_TIME_RENDERLOOP,
734 "[window %p][gui thread] syncAndRender: frame rendered in %dms, polish=%d, sync=%d, render=%d, swap=%d, perWindowFrameDelta=%d",
736 int(swapTime / 1000000),
737 int(polishTime / 1000000),
738 int((syncTime - polishTime) / 1000000),
739 int((renderTime - syncTime) / 1000000),
740 int((swapTime - renderTime) / 1000000),
741 int(data.timeBetweenRenders.restart()));
742 if (!qFuzzyIsNull(lastCompletedGpuTime) && cd->graphicsConfig.timestampsEnabled()) {
743 qCDebug(QSG_LOG_TIME_RENDERLOOP,
"[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms",
745 lastCompletedGpuTime * 1000.0);