Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsgrenderloop.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsgrenderloop_p.h"
6#include "qsgrhisupport_p.h"
7#include <private/qquickanimatorcontroller_p.h>
8
9#include <QtCore/QCoreApplication>
10#include <QtCore/QElapsedTimer>
11#include <QtCore/QLibraryInfo>
12#include <QtCore/private/qabstractanimation_p.h>
13
14#include <QtGui/QOffscreenSurface>
15#include <QtGui/private/qguiapplication_p.h>
16#include <qpa/qplatformintegration.h>
17#include <QPlatformSurfaceEvent>
18
19#include <QtQml/private/qqmlglobal_p.h>
20
21#include <QtQuick/QQuickWindow>
22#include <QtQuick/private/qquickwindow_p.h>
23#include <QtQuick/private/qquickitem_p.h>
24#include <QtQuick/private/qsgcontext_p.h>
25#include <QtQuick/private/qsgrenderer_p.h>
26#include <private/qquickprofiler_p.h>
27#include <qtquick_tracepoints_p.h>
28
29#include <private/qsgrhishadereffectnode_p.h>
30
31#include <private/qsgdefaultrendercontext_p.h>
32
33#ifdef Q_OS_WIN
34#include <QtCore/qt_windows.h>
35#endif
36
38
39extern bool qsg_useConsistentTiming();
40
41#define ENABLE_DEFAULT_BACKEND
42
43Q_TRACE_POINT(qtquick, QSG_renderWindow_entry)
44Q_TRACE_POINT(qtquick, QSG_renderWindow_exit)
45Q_TRACE_POINT(qtquick, QSG_polishItems_entry)
46Q_TRACE_POINT(qtquick, QSG_polishItems_exit)
47Q_TRACE_POINT(qtquick, QSG_sync_entry)
48Q_TRACE_POINT(qtquick, QSG_sync_exit)
49Q_TRACE_POINT(qtquick, QSG_render_entry)
50Q_TRACE_POINT(qtquick, QSG_render_exit)
51Q_TRACE_POINT(qtquick, QSG_swap_entry)
52Q_TRACE_POINT(qtquick, QSG_swap_exit)
53
54
55/*
56 - Uses one QRhi per window. (and so each window has its own QOpenGLContext or ID3D11Device(Context) etc.)
57 - Animations are advanced using the standard timer (no custom animation
58 driver is installed), so QML animations run as expected even when vsync
59 throttling is broken.
60 */
61
62DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
63DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk
64
65QSGRenderLoop *QSGRenderLoop::s_instance = nullptr;
66
68{
69}
70
72{
73 if (!s_instance)
74 return;
75 for (QQuickWindow *w : s_instance->windows()) {
77 if (wd->windowManager == s_instance) {
78 s_instance->windowDestroyed(w);
79 wd->windowManager = nullptr;
80 }
81 }
82 delete s_instance;
83 s_instance = nullptr;
84}
85
87{
88#ifdef ENABLE_DEFAULT_BACKEND
90#else
92#endif
93}
94
96{
97 Q_ASSERT(job);
98#ifdef ENABLE_DEFAULT_BACKEND
101 if (cd->rhi)
103 job->run();
104#else
106 job->run();
107#endif
108 delete job;
109}
110
111#ifdef ENABLE_DEFAULT_BACKEND
113{
115public:
118
119 void show(QQuickWindow *window) override;
120 void hide(QQuickWindow *window) override;
121
122 void windowDestroyed(QQuickWindow *window) override;
123
125 void exposureChanged(QQuickWindow *window) override;
126 QImage grab(QQuickWindow *window) override;
127
128 void maybeUpdate(QQuickWindow *window) override;
129 void update(QQuickWindow *window) override { maybeUpdate(window); } // identical for this implementation.
130 void handleUpdateRequest(QQuickWindow *) override;
131
132 void releaseResources(QQuickWindow *) override;
133
134 QAnimationDriver *animationDriver() const override { return nullptr; }
135
136 QSGContext *sceneGraphContext() const override;
138
140 void handleDeviceLoss();
141
142 bool eventFilter(QObject *watched, QEvent *event) override;
143
144 struct WindowData {
149 { }
150 QRhi *rhi = nullptr;
151 bool ownRhi = true;
154 int sampleCount = 1;
157 bool rhiDoomed : 1;
158 };
159
161
163
167
168 bool m_inPolish = false;
169};
170#endif
171
173{
174 if (!s_instance) {
175
177
178 s_instance = QSGContext::createWindowManager();
179#ifdef ENABLE_DEFAULT_BACKEND
180 if (!s_instance) {
182
183 QSGRenderLoopType loopType;
184 if (rhiSupport->rhiBackend() != QRhi::OpenGLES2) {
185 loopType = ThreadedRenderLoop;
186 } else {
188 loopType = ThreadedRenderLoop;
189 else
190 loopType = BasicRenderLoop;
191 }
192
193 switch (rhiSupport->rhiBackend()) {
194 case QRhi::Null:
195 loopType = BasicRenderLoop;
196 break;
197
198 case QRhi::D3D11:
199 // The threaded loop's model may not be suitable for DXGI
200 // due to the possibility of having the main thread (with
201 // the Windows message pump) blocked while issuing a
202 // Present on the render thread. However, according to the
203 // docs this can be a problem for fullscreen swapchains
204 // only. So leave threaded enabled by default for now and
205 // revisit later if there are problems.
206 break;
207
208 default:
209 break;
210 }
211
212 // The environment variables can always override. This is good
213 // because in some situations it makes perfect sense to try out a
214 // render loop that is otherwise disabled by default.
215
216 if (qmlNoThreadedRenderer())
217 loopType = BasicRenderLoop;
218 else if (qmlForceThreadedRenderer())
219 loopType = ThreadedRenderLoop;
220
221 if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_RENDER_LOOP"))) {
222 const QByteArray loopName = qgetenv("QSG_RENDER_LOOP");
223 if (loopName == "windows") {
224 qWarning("The 'windows' render loop is no longer supported. Using 'basic' instead.");
225 loopType = BasicRenderLoop;
226 } else if (loopName == "basic") {
227 loopType = BasicRenderLoop;
228 } else if (loopName == "threaded") {
229 loopType = ThreadedRenderLoop;
230 }
231 }
232
233 switch (loopType) {
234#if QT_CONFIG(thread)
236 qCDebug(QSG_LOG_INFO, "threaded render loop");
237 s_instance = new QSGThreadedRenderLoop();
238 break;
239#endif
240 default:
241 qCDebug(QSG_LOG_INFO, "basic render loop");
242 s_instance = new QSGGuiThreadRenderLoop();
243 break;
244 }
245 }
246#endif
248 }
249
250 return s_instance;
251}
252
254{
255 Q_ASSERT(!s_instance);
256 s_instance = instance;
257}
258
260{
261 QString translatedMessage;
262 QString untranslatedMessage;
264 &translatedMessage,
265 &untranslatedMessage);
266 // If there is a slot connected to the error signal, emit it and leave it to
267 // the application to do something with the message. If nothing is connected,
268 // show a message on our own and terminate.
269 const bool signalEmitted =
270 QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
271 translatedMessage);
272#if defined(Q_OS_WIN)
273 if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
274 MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
276 MB_OK | MB_ICONERROR);
277 }
278#endif // Q_OS_WIN
279 if (!signalEmitted)
280 qFatal("%s", qPrintable(untranslatedMessage));
281}
282
283#ifdef ENABLE_DEFAULT_BACKEND
285{
288 qCDebug(QSG_LOG_INFO, "using fixed animation steps");
289 }
290
292}
293
295{
297 delete sg;
298}
299
301{
302 if (!m_windows.contains(window))
303 m_windows.insert(window, {});
304
305 m_windows[window].timeBetweenRenders.start();
307}
308
310{
312 cd->fireAboutToStop();
313 auto it = m_windows.find(window);
314 if (it != m_windows.end())
315 it->updatePending = false;
316}
317
319{
320 hide(window);
321
322 WindowData data = m_windows.value(window, {});
323 m_windows.remove(window);
324
326
327 if (data.rhi) {
328 // Direct OpenGL calls in user code need a current context, like
329 // when rendering; ensure this (no-op when not running on GL).
330 // Also works when there is no handle() anymore.
331 data.rhi->makeThreadLocalNativeContextCurrent();
332 }
333
334 if (d->swapchain) {
335 if (window->handle()) {
336 // We get here when exiting via QCoreApplication::quit() instead of
337 // through QWindow::close().
339 } else {
340 qWarning("QSGGuiThreadRenderLoop cleanup with QQuickWindow %p swapchain %p still alive, this should not happen.",
341 window, d->swapchain);
342 }
343 }
344
345 d->cleanupNodesOnShutdown();
346
347#if QT_CONFIG(quick_shadereffect)
349#endif
350
351 if (data.rc) {
352 data.rc->invalidate();
353 delete data.rc;
354 }
355
356 if (data.ownRhi)
357 QSGRhiSupport::instance()->destroyRhi(data.rhi, d->graphicsConfig);
358
359 d->rhi = nullptr;
360
361 d->animationController.reset();
362
363 if (m_windows.isEmpty()) {
364 delete offscreenSurface;
365 offscreenSurface = nullptr;
366 }
367}
368
370{
371 qWarning("Graphics device lost, cleaning up scenegraph and releasing RHIs");
372
373 for (auto it = m_windows.begin(), itEnd = m_windows.end(); it != itEnd; ++it) {
374 if (!it->rhi || !it->rhi->isDeviceLost())
375 return;
376
378
379 if (it->rc)
380 it->rc->invalidate();
381
382 releaseSwapchain(it.key());
383 it->rhiDeviceLost = true;
384
385 if (it->ownRhi)
387 it->rhi = nullptr;
388 }
389}
390
392{
394 delete wd->rpDescForSwapchain;
395 wd->rpDescForSwapchain = nullptr;
396 delete wd->swapchain;
397 wd->swapchain = nullptr;
398 delete wd->depthStencilForSwapchain;
399 wd->depthStencilForSwapchain = nullptr;
401}
402
404{
405 switch (event->type()) {
407 // this is the proper time to tear down the swapchain (while the native window and surface are still around)
408 if (static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
409 QQuickWindow *w = qobject_cast<QQuickWindow *>(watched);
410 if (w)
412 // keep this filter on the window - needed for uncommon but valid
413 // sequences of calls like window->destroy(); window->show();
414 }
415 break;
416 default:
417 break;
418 }
419 return QObject::eventFilter(watched, event);
420}
421
423{
426 bool ok = data.rhi != nullptr;
427
428 if (!data.rhi) {
429 // This block below handles both the initial QRhi initialization and
430 // also the subsequent reinitialization attempts after a device lost
431 // (reset) situation.
432
433 if (data.rhiDoomed) // no repeated attempts if the initial attempt failed
434 return false;
435
436 if (!offscreenSurface)
438
440 data.rhi = rhiResult.rhi;
441 data.ownRhi = rhiResult.own;
442
443 if (data.rhi) {
444 data.rhiDeviceLost = false;
445
446 ok = true;
447 // We need to guarantee that sceneGraphInitialized is
448 // emitted with a context current, if running with OpenGL.
449 data.rhi->makeThreadLocalNativeContextCurrent();
450
451 // The sample count cannot vary between windows as we use the same
452 // rendercontext for all of them. Decide it here and now.
453 data.sampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, data.rhi);
454
455 cd->rhi = data.rhi; // set this early in case something hooked up to rc initialized() accesses it
456
458 rcParams.rhi = data.rhi;
459 rcParams.sampleCount = data.sampleCount;
460 rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
461 rcParams.maybeSurface = window;
462 cd->context->initialize(&rcParams);
463 } else {
464 if (!data.rhiDeviceLost) {
465 data.rhiDoomed = true;
467 }
468 // otherwise no error, just return false so that we will retry on a subsequent rendering attempt
469 }
470 }
471
472 if (data.rhi && !cd->swapchain) {
473 // if it's not the first window then the rhi is not yet stored to
474 // QQuickWindowPrivate, do it now
475 cd->rhi = data.rhi;
476
477 // Unlike the threaded render loop, we use the same rhi for all windows
478 // and so createRhi() is called only once. Certain initialization may
479 // need to be done on a per window basis still, so make sure it is done.
480 rhiSupport->prepareWindowForRhi(window);
481
482 QRhiSwapChain::Flags flags = QRhiSwapChain::UsedAsTransferSource; // may be used in a grab
483 const QSurfaceFormat requestedFormat = window->requestedFormat();
484
485 // QQ is always premul alpha. Decide based on alphaBufferSize in
486 // requestedFormat(). (the platform plugin can override format() but
487 // what matters here is what the application wanted, hence using the
488 // requested one)
489 const bool alpha = requestedFormat.alphaBufferSize() > 0;
490 if (alpha)
492
493 // Request NoVSync if swap interval was set to 0 (either by the app or
494 // by QSG_NO_VSYNC). What this means in practice is another question,
495 // but at least we tried.
496 if (requestedFormat.swapInterval() == 0) {
497 qCDebug(QSG_LOG_INFO, "Swap interval is 0, attempting to disable vsync when presenting.");
499 }
500
502 static bool depthBufferEnabled = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
503 if (depthBufferEnabled) {
505 QSize(),
506 data.sampleCount,
509 }
511 rhiSupport->applySwapChainFormat(cd->swapchain, window);
512 qCDebug(QSG_LOG_INFO, "MSAA sample count for the swapchain is %d. Alpha channel requested = %s",
513 data.sampleCount, alpha ? "yes" : "no");
514 cd->swapchain->setSampleCount(data.sampleCount);
518
519 window->installEventFilter(this);
520 }
521
522 if (!data.rc) {
523 QSGRenderContext *rc = cd->context;
525 data.rc = rc;
526 if (!data.rc)
527 qWarning("No QSGRenderContext for window %p, this should not happen", window);
528 }
529
530 return ok;
531}
532
534{
535 auto winDataIt = m_windows.find(window);
536 if (winDataIt == m_windows.end())
537 return;
538
539 WindowData &data(*winDataIt);
540 bool alsoSwap = data.updatePending;
541 data.updatePending = false;
542
544 if (!cd->isRenderable())
545 return;
546
547 if (!cd->updatesEnabled)
548 return;
549
550 if (!ensureRhi(window, data))
551 return;
552
553 bool lastDirtyWindow = true;
554 for (auto it = m_windows.cbegin(), end = m_windows.cend(); it != end; ++it) {
555 if (it->updatePending) {
556 lastDirtyWindow = false;
557 break;
558 }
559 }
560
562 // Event delivery/processing triggered the window to be deleted or stop rendering.
563 if (!m_windows.contains(window))
564 return;
565
566 QSize effectiveOutputSize; // always prefer what the surface tells us, not the QWindow
567 if (cd->swapchain) {
568 effectiveOutputSize = cd->swapchain->surfacePixelSize();
569 // An update request could still be delivered right before we get an
570 // unexpose. With Vulkan on Windows for example attempting to render
571 // leads to failures at this stage since the surface size is already 0.
572 if (effectiveOutputSize.isEmpty())
573 return;
574 }
575
576 Q_TRACE_SCOPE(QSG_renderWindow);
577 QElapsedTimer renderTimer;
578 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
579 const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
580 if (profileFrames)
581 renderTimer.start();
582 Q_TRACE(QSG_polishItems_entry);
583 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
584
585 m_inPolish = true;
586 cd->polishItems();
587 m_inPolish = false;
588
589 if (profileFrames)
590 polishTime = renderTimer.nsecsElapsed();
591
592 Q_TRACE(QSG_polishItems_exit);
593 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
594 QQuickProfiler::SceneGraphRenderLoopFrame,
595 QQuickProfiler::SceneGraphPolishPolish);
596 Q_TRACE(QSG_sync_entry);
597
598 emit window->afterAnimating();
599
600 // Begin the frame before syncing -> sync is where we may invoke
601 // updatePaintNode() on the items and they may want to do resource updates.
602 // Also relevant for applications that connect to the before/afterSynchronizing
603 // signals and want to do graphics stuff already there.
604 if (cd->swapchain) {
605 Q_ASSERT(!effectiveOutputSize.isEmpty());
606 const QSize previousOutputSize = cd->swapchain->currentPixelSize();
607 if (previousOutputSize != effectiveOutputSize || cd->swapchainJustBecameRenderable) {
609 qCDebug(QSG_LOG_RENDERLOOP, "just became exposed");
610
612 if (!cd->hasActiveSwapchain && data.rhi->isDeviceLost()) {
614 return;
615 }
616
619
620 if (cd->hasActiveSwapchain) {
621 // surface size atomicity: now that buildOrResize() succeeded,
622 // query the size that was used in there by the swapchain, and
623 // that is the size we will use while preparing the next frame.
624 effectiveOutputSize = cd->swapchain->currentPixelSize();
625 qCDebug(QSG_LOG_RENDERLOOP) << "rhi swapchain size" << effectiveOutputSize;
626 } else {
627 qWarning("Failed to build or resize swapchain");
628 }
629 }
630
631 emit window->beforeFrameBegin();
632
633 Q_ASSERT(data.rhi == cd->rhi);
634 QRhi::FrameOpResult frameResult = data.rhi->beginFrame(cd->swapchain);
635 if (frameResult != QRhi::FrameOpSuccess) {
636 if (frameResult == QRhi::FrameOpDeviceLost)
638 else if (frameResult == QRhi::FrameOpError)
639 qWarning("Failed to start frame");
640 // out of date is not worth warning about - it may happen even during resizing on some platforms
641 emit window->afterFrameEnd();
642 return;
643 }
644 }
645
646 // Enable external OpenGL rendering connected to one of the
647 // QQuickWindow signals (beforeSynchronizing, beforeRendering,
648 // etc.) to function like it did on the direct OpenGL path,
649 // i.e. ensure there is a context current, just in case.
650 data.rhi->makeThreadLocalNativeContextCurrent();
651
652 cd->syncSceneGraph();
653 if (lastDirtyWindow)
654 data.rc->endSync();
655
656 if (profileFrames)
657 syncTime = renderTimer.nsecsElapsed();
658
659 Q_TRACE(QSG_sync_exit);
660 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
661 QQuickProfiler::SceneGraphRenderLoopSync);
662 Q_TRACE(QSG_render_entry);
663
664 cd->renderSceneGraph();
665
666 if (profileFrames)
667 renderTime = renderTimer.nsecsElapsed();
668 Q_TRACE(QSG_render_exit);
669 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
670 QQuickProfiler::SceneGraphRenderLoopRender);
671 Q_TRACE(QSG_swap_entry);
672
673 const bool needsPresent = alsoSwap && window->isVisible();
674 double lastCompletedGpuTime = 0;
675 if (cd->swapchain) {
676 QRhi::EndFrameFlags flags;
677 if (!needsPresent)
679 QRhi::FrameOpResult frameResult = data.rhi->endFrame(cd->swapchain, flags);
680 if (frameResult != QRhi::FrameOpSuccess) {
681 if (frameResult == QRhi::FrameOpDeviceLost)
683 else if (frameResult == QRhi::FrameOpError)
684 qWarning("Failed to end frame");
685 }
686 lastCompletedGpuTime = cd->swapchain->currentFrameCommandBuffer()->lastCompletedGpuTime();
687 }
688 if (needsPresent)
689 cd->fireFrameSwapped();
690
691 emit window->afterFrameEnd();
692
693 qint64 swapTime = 0;
694 if (profileFrames)
695 swapTime = renderTimer.nsecsElapsed();
696
697 Q_TRACE(QSG_swap_exit);
698 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
699 QQuickProfiler::SceneGraphRenderLoopSwap);
700
701 if (profileFrames) {
702 qCDebug(QSG_LOG_TIME_RENDERLOOP,
703 "[window %p][gui thread] syncAndRender: frame rendered in %dms, polish=%d, sync=%d, render=%d, swap=%d, perWindowFrameDelta=%d",
704 window,
705 int(swapTime / 1000000),
706 int(polishTime / 1000000),
707 int((syncTime - polishTime) / 1000000),
708 int((renderTime - syncTime) / 1000000),
709 int((swapTime - renderTime) / 1000000),
710 int(data.timeBetweenRenders.restart()));
711 if (!qFuzzyIsNull(lastCompletedGpuTime) && cd->graphicsConfig.isTimestampsEnabled()) {
712 qCDebug(QSG_LOG_TIME_RENDERLOOP, "[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms",
713 window,
714 lastCompletedGpuTime * 1000.0);
715 }
716 }
717
718 // Might have been set during syncSceneGraph()
719 if (data.updatePending)
721}
722
724{
726
727 // This is tricker than used to be. We want to detect having an empty
728 // surface size (which may be the case even when window->size() is
729 // non-empty, on some platforms with some graphics APIs!) as well as the
730 // case when the window just became "newly exposed" (e.g. after a
731 // minimize-restore on Windows, or when switching between fully obscured -
732 // not fully obscured on macOS)
733
734 if (!window->isExposed() || (wd->hasActiveSwapchain && wd->swapchain->surfacePixelSize().isEmpty()))
735 wd->hasRenderableSwapchain = false;
736
737 if (window->isExposed() && !wd->hasRenderableSwapchain && wd->hasActiveSwapchain
739 {
740 wd->hasRenderableSwapchain = true;
742 }
743
744 auto winDataIt = m_windows.find(window);
745 if (winDataIt != m_windows.end()) {
746 if (window->isExposed() && (!winDataIt->rhi || !wd->hasActiveSwapchain || wd->hasRenderableSwapchain)) {
747 winDataIt->updatePending = true;
749 }
750 }
751}
752
754{
755 auto winDataIt = m_windows.find(window);
756 if (winDataIt == m_windows.end())
757 return QImage();
758
759 if (!ensureRhi(window, *winDataIt))
760 return QImage();
761
763 m_inPolish = true;
764 cd->polishItems();
765 m_inPolish = false;
766
767 // The assumption is that the swapchain is usable since on expose we do a
768 // renderWindow() so one cannot get to grab() without having done at least
769 // one on-screen frame.
770 cd->rhi->beginFrame(cd->swapchain);
771 cd->rhi->makeThreadLocalNativeContextCurrent(); // for custom GL rendering before/during/after sync
772 cd->syncSceneGraph();
773 cd->renderSceneGraph();
776
777 image.setDevicePixelRatio(window->effectiveDevicePixelRatio());
778 return image;
779}
780
782{
783 auto winDataIt = m_windows.find(window);
784 if (winDataIt == m_windows.end())
785 return;
786
787 // Even if the window is not renderable,
788 // renderWindow() called on different window
789 // should not delete QSGTexture's
790 // from this unrenderable window.
791 winDataIt->updatePending = true;
792
794 if (!cd->isRenderable())
795 return;
796
797 // An updatePolish() implementation may call update() to get the QQuickItem
798 // dirtied. That's fine but it also leads to calling this function.
799 // Requesting another update is a waste then since the updatePolish() call
800 // will be followed up with a round of sync and render.
801 if (m_inPolish)
802 return;
803
804 window->requestUpdate();
805}
806
808{
809 return sg;
810}
811
813{
816 return rc;
817}
818
820{
821 // No full invalidation of the rendercontext, just clear some caches.
823 emit d->context->releaseCachedResourcesRequested();
824 if (d->renderer)
825 d->renderer->releaseCachedResources();
826#if QT_CONFIG(quick_shadereffect)
828#endif
829}
830
832{
834}
835
836#endif // ENABLE_DEFAULT_BACKEND
837
839
840#include "qsgrenderloop.moc"
841#include "moc_qsgrenderloop_p.cpp"
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
QString applicationName
the name of this application
\inmodule QtCore
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
\inmodule QtCore
Definition qcoreevent.h:45
@ PlatformSurface
Definition qcoreevent.h:278
static QPlatformIntegration * platformIntegration()
\inmodule QtCore
Definition qhash.h:818
\inmodule QtGui
Definition qimage.h:37
static bool isDebugBuild() noexcept Q_DECL_CONST_FUNCTION
\inmodule QtCore
Definition qobject.h:90
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
Definition qobject.cpp:1518
\inmodule QtGui
The QPlatformSurfaceEvent class is used to notify about native platform surface events....
Definition qevent.h:530
void flushFrameSynchronousEvents(QQuickWindow *win)
QRhiRenderPassDescriptor * rpDescForSwapchain
bool emitError(QQuickWindow::SceneGraphError error, const QString &msg)
QQuickGraphicsConfiguration graphicsConfig
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGRenderContext * context
QRhiRenderBuffer * depthStencilForSwapchain
static void rhiCreationFailureMessage(const QString &backendName, QString *translatedMessage, QString *untranslatedMessage)
QQuickDeliveryAgentPrivate * deliveryAgentPrivate() const
QRhiSwapChain * swapchain
QSGRenderLoop * windowManager
bool isRenderable() const
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
double lastCompletedGpuTime()
Definition qrhi.cpp:9561
@ UsedWithSwapChainOnly
Definition qrhi.h:1079
QRhi * rhi() const
Definition qrhi.cpp:3477
QSize currentPixelSize() const
Definition qrhi.h:1559
void setDepthStencil(QRhiRenderBuffer *ds)
Sets the renderbuffer ds for use as a depth-stencil buffer.
Definition qrhi.h:1551
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor()=0
virtual bool createOrResize()=0
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
virtual QSize surfacePixelSize()=0
@ UsedAsTransferSource
Definition qrhi.h:1519
@ SurfaceHasPreMulAlpha
Definition qrhi.h:1516
void setSampleCount(int samples)
Sets the sample count.
Definition qrhi.h:1554
void setFlags(Flags f)
Sets the flags f.
Definition qrhi.h:1545
void setWindow(QWindow *window)
Sets the window.
Definition qrhi.h:1539
virtual QRhiCommandBuffer * currentFrameCommandBuffer()=0
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Associates with the QRhiRenderPassDescriptor desc.
Definition qrhi.h:1557
\inmodule QtGui
Definition qrhi.h:1767
bool makeThreadLocalNativeContextCurrent()
With OpenGL this makes the OpenGL context current on the current thread.
Definition qrhi.cpp:9729
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition qrhi.cpp:10106
@ Null
Definition qrhi.h:1770
@ D3D11
Definition qrhi.h:1773
@ OpenGLES2
Definition qrhi.h:1772
FrameOpResult beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags={})
Starts a new frame targeting the next available buffer of swapChain.
Definition qrhi.cpp:10308
QRhiSwapChain * newSwapChain()
Definition qrhi.cpp:10256
FrameOpResult endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags={})
Ends, commits, and presents a frame that was started in the last beginFrame() on swapChain.
Definition qrhi.cpp:10343
@ SkipPresent
Definition qrhi.h:1842
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1786
@ FrameOpSuccess
Definition qrhi.h:1787
@ FrameOpDeviceLost
Definition qrhi.h:1790
@ FrameOpError
Definition qrhi.h:1788
\inmodule QtCore
Definition qrunnable.h:18
virtual void run()=0
Implement this pure virtual function in your subclass.
The QSGContext holds the scene graph entry points for one QML engine.
virtual QSGRenderContext * createRenderContext()=0
static QSGRenderLoop * createWindowManager()
Calls into the scene graph adaptation if available and creates a hardware specific window manager.
static QSGContext * createDefaultContext()
Creates a default scene graph context for the current hardware.
QAnimationDriver * animationDriver() const override
void update(QQuickWindow *window) override
void renderWindow(QQuickWindow *window)
void releaseSwapchain(QQuickWindow *window)
void show(QQuickWindow *window) override
bool eventFilter(QObject *watched, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
QSGRenderContext * createRenderContext(QSGContext *) const override
void windowDestroyed(QQuickWindow *window) override
bool ensureRhi(QQuickWindow *window, WindowData &data)
QOffscreenSurface * offscreenSurface
void releaseResources(QQuickWindow *) override
void exposureChanged(QQuickWindow *window) override
QSGContext * sceneGraphContext() const override
QHash< QQuickWindow *, WindowData > m_windows
void handleUpdateRequest(QQuickWindow *) override
void hide(QQuickWindow *window) override
QSet< QSGRenderContext * > pendingRenderContexts
QImage grab(QQuickWindow *window) override
void maybeUpdate(QQuickWindow *window) override
virtual void initialize(const InitParams *params)
static void setInstance(QSGRenderLoop *instance)
virtual void postJob(QQuickWindow *window, QRunnable *job)
static QSGRenderLoop * instance()
virtual QSurface::SurfaceType windowSurfaceType() const
virtual void windowDestroyed(QQuickWindow *window)=0
virtual int flags() const
QSet< QQuickWindow * > windows() const
void handleContextCreationFailure(QQuickWindow *window)
static void cleanup()
static void garbageCollectMaterialTypeCache(void *materialTypeCacheKey)
static void resetMaterialTypeCache(void *materialTypeCacheKey)
QOffscreenSurface * maybeCreateOffscreenSurface(QWindow *window)
void applySwapChainFormat(QRhiSwapChain *scWithWindowSet, QQuickWindow *window)
static void checkEnvQSgInfo()
static int chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi)
void prepareWindowForRhi(QQuickWindow *window)
static QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src=nullptr)
QRhi::Implementation rhiBackend() const
void destroyRhi(QRhi *rhi, const QQuickGraphicsConfiguration &config)
static QSGRhiSupport * instance()
RhiCreateResult createRhi(QQuickWindow *window, QSurface *offscreenSurface)
QSurface::SurfaceType windowSurfaceType() const
Definition qset.h:18
bool remove(const T &value)
Definition qset.h:63
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qsize.h:25
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
int alphaBufferSize() const
Get the size in bits of the alpha channel of the color buffer.
int swapInterval() const
Returns the swap interval.
SurfaceType
The SurfaceType enum describes what type of surface this is.
Definition qsurface.h:30
@ RasterSurface
Definition qsurface.h:31
static QUnifiedTimer * instance()
void setConsistentTiming(bool consistent)
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Definition image.cpp:4
#define Q_UNLIKELY(x)
void qAddPostRoutine(QtCleanUpFunction p)
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
#define qWarning
Definition qlogging.h:162
#define qFatal
Definition qlogging.h:164
#define qCDebug(category,...)
GLfloat GLfloat GLfloat w
[0]
GLuint GLuint end
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
struct _cl_event * event
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
#define DEFINE_BOOL_CONFIG_OPTION(name, var)
#define Q_QUICK_SG_PROFILE_END(Type, position)
#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2, position)
#define Q_QUICK_SG_PROFILE_RECORD(Type, position)
#define Q_QUICK_SG_PROFILE_START(Type)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE bool qsg_useConsistentTiming()
QSGRenderLoopType
@ BasicRenderLoop
@ ThreadedRenderLoop
#define qPrintable(string)
Definition qstring.h:1391
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define Q_OBJECT
#define emit
#define Q_UNUSED(x)
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
long long qint64
Definition qtypes.h:55
view show()
[18] //! [19]
edit hide()
aWidget window() -> setWindowTitle("New Window Title")
[2]