7#include <private/qquickanimatorcontroller_p.h>
9#include <QtCore/QCoreApplication>
10#include <QtCore/QElapsedTimer>
11#include <QtCore/QLibraryInfo>
12#include <QtCore/private/qabstractanimation_p.h>
14#include <QtGui/QOffscreenSurface>
15#include <QtGui/private/qguiapplication_p.h>
16#include <qpa/qplatformintegration.h>
17#include <QPlatformSurfaceEvent>
19#include <QtQml/private/qqmlglobal_p.h>
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>
29#include <private/qsgrhishadereffectnode_p.h>
31#include <private/qsgdefaultrendercontext_p.h>
34#include <QtCore/qt_windows.h>
41#define ENABLE_DEFAULT_BACKEND
78 s_instance->windowDestroyed(
w);
88#ifdef ENABLE_DEFAULT_BACKEND
98#ifdef ENABLE_DEFAULT_BACKEND
111#ifdef ENABLE_DEFAULT_BACKEND
182#ifdef ENABLE_DEFAULT_BACKEND
219 if (qmlNoThreadedRenderer())
221 else if (qmlForceThreadedRenderer())
226 if (loopName ==
"windows") {
227 qWarning(
"The 'windows' render loop is no longer supported. Using 'basic' instead.");
229 }
else if (loopName ==
"basic") {
231 }
else if (loopName ==
"threaded") {
239 qCDebug(QSG_LOG_INFO,
"threaded render loop");
244 qCDebug(QSG_LOG_INFO,
"basic render loop");
267 static QSet<QQuickWindow *> recurseGuard;
268 if (recurseGuard.contains(
window))
271 recurseGuard.insert(
window);
277 &untranslatedMessage);
281 const bool signalEmitted =
286 MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
288 MB_OK | MB_ICONERROR);
294 recurseGuard.remove(
window);
297#ifdef ENABLE_DEFAULT_BACKEND
302 qCDebug(QSG_LOG_INFO,
"using fixed animation steps");
329 it->updatePending =
false;
345 data.rhi->makeThreadLocalNativeContextCurrent();
354 qWarning(
"QSGGuiThreadRenderLoop cleanup with QQuickWindow %p swapchain %p still alive, this should not happen.",
359 d->cleanupNodesOnShutdown();
361#if QT_CONFIG(quick_shadereffect)
366 data.rc->invalidate();
375 d->animationController.reset();
389 it->rc->invalidate();
400 qWarning(
"Graphics device lost, cleaning up scenegraph and releasing RHIs");
403 if (!
it->rhi || !
it->rhi->isDeviceLost())
409 it->rc->invalidate();
412 it->rhiDeviceLost =
true;
434 switch (
event->type()) {
455 bool ok =
data.rhi !=
nullptr;
471 data.ownRhi = rhiResult.own;
474 data.rhiDeviceLost =
false;
489 rcParams.sampleCount =
data.sampleCount;
490 rcParams.initialSurfacePixelSize =
window->size() *
window->effectiveDevicePixelRatio();
491 rcParams.maybeSurface =
window;
494 if (!
data.rhiDeviceLost) {
495 data.rhiDoomed =
true;
527 qCDebug(QSG_LOG_INFO,
"Swap interval is 0, attempting to disable vsync when presenting.");
533 if (depthBufferEnabled) {
542 qCDebug(QSG_LOG_INFO,
"MSAA sample count for the swapchain is %d. Alpha channel requested = %s",
549 window->installEventFilter(
this);
557 qWarning(
"No QSGRenderContext for window %p, this should not happen",
window);
570 bool alsoSwap =
data.updatePending;
571 data.updatePending =
false;
583 bool lastDirtyWindow =
true;
585 if (
it->updatePending) {
586 lastDirtyWindow =
false;
596 QSize effectiveOutputSize;
602 if (effectiveOutputSize.isEmpty())
608 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
609 const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
612 Q_TRACE(QSG_polishItems_entry);
620 polishTime = renderTimer.nsecsElapsed();
624 QQuickProfiler::SceneGraphRenderLoopFrame,
625 QQuickProfiler::SceneGraphPolishPolish);
635 Q_ASSERT(!effectiveOutputSize.isEmpty());
640 qCDebug(QSG_LOG_RENDERLOOP,
"just became exposed");
644 if (
data.rhi->isDeviceLost()) {
648 qWarning(
"Failed to create swapchain."
649 " Retrying by requesting a software rasterizer, if applicable for the 3D API implementation.");
664 qCDebug(QSG_LOG_RENDERLOOP) <<
"rhi swapchain size" << effectiveOutputSize;
666 qWarning(
"Failed to build or resize swapchain");
689 data.rhi->makeThreadLocalNativeContextCurrent();
696 syncTime = renderTimer.nsecsElapsed();
700 QQuickProfiler::SceneGraphRenderLoopSync);
706 renderTime = renderTimer.nsecsElapsed();
709 QQuickProfiler::SceneGraphRenderLoopRender);
712 const bool needsPresent = alsoSwap &&
window->isVisible();
713 double lastCompletedGpuTime = 0;
715 QRhi::EndFrameFlags
flags;
735 swapTime = renderTimer.nsecsElapsed();
739 QQuickProfiler::SceneGraphRenderLoopSwap);
742 qCDebug(QSG_LOG_TIME_RENDERLOOP,
743 "[window %p][gui thread] syncAndRender: frame rendered in %dms, polish=%d, sync=%d, render=%d, swap=%d, perWindowFrameDelta=%d",
745 int(swapTime / 1000000),
746 int(polishTime / 1000000),
747 int((syncTime - polishTime) / 1000000),
748 int((renderTime - syncTime) / 1000000),
749 int((swapTime - renderTime) / 1000000),
750 int(
data.timeBetweenRenders.restart()));
752 qCDebug(QSG_LOG_TIME_RENDERLOOP,
"[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms",
754 lastCompletedGpuTime * 1000.0);
759 if (
data.updatePending)
787 winDataIt->updatePending =
true;
817 image.setDevicePixelRatio(
window->effectiveDevicePixelRatio());
831 winDataIt->updatePending =
true;
863 emit d->context->releaseCachedResourcesRequested();
865 d->renderer->releaseCachedResources();
866#if QT_CONFIG(quick_shadereffect)
880#include "qsgrenderloop.moc"
881#include "moc_qsgrenderloop_p.cpp"
QString applicationName
the name of this application
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
static QPlatformIntegration * platformIntegration()
static bool isDebugBuild() noexcept Q_DECL_CONST_FUNCTION
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
void flushFrameSynchronousEvents(QQuickWindow *win)
bool timestampsEnabled() const
QRhiRenderPassDescriptor * rpDescForSwapchain
QQuickGraphicsConfiguration graphicsConfig
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGRenderContext * context
uint swapchainJustBecameRenderable
QRhiRenderBuffer * depthStencilForSwapchain
static void rhiCreationFailureMessage(const QString &backendName, QString *translatedMessage, QString *untranslatedMessage)
QQuickDeliveryAgentPrivate * deliveryAgentPrivate() const
QRhiSwapChain * swapchain
uint hasRenderableSwapchain
QSGRenderLoop * windowManager
bool isRenderable() const
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
QSize currentPixelSize() const
void setDepthStencil(QRhiRenderBuffer *ds)
Sets the renderbuffer ds for use as a depth-stencil buffer.
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
void setSampleCount(int samples)
Sets the sample count.
void setFlags(Flags f)
Sets the flags f.
void setWindow(QWindow *window)
Sets the window.
virtual QRhiCommandBuffer * currentFrameCommandBuffer()=0
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Associates with the QRhiRenderPassDescriptor desc.
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
bool makeThreadLocalNativeContextCurrent()
With OpenGL this makes the OpenGL context current on the current thread.
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
FrameOpResult beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags={})
Starts a new frame targeting the next available buffer of swapChain.
QRhiSwapChain * newSwapChain()
FrameOpResult endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags={})
Ends, commits, and presents a frame that was started in the last beginFrame() on swapChain.
FrameOpResult
Describes the result of operations that can have a soft failure.
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.
~QSGGuiThreadRenderLoop()
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
bool swRastFallbackDueToSwapchainFailure
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 int flags() const
void handleContextCreationFailure(QQuickWindow *window)
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)
bool attemptReinitWithSwRastUponFail() const
void prepareWindowForRhi(QQuickWindow *window)
RhiCreateResult createRhi(QQuickWindow *window, QSurface *offscreenSurface, bool forcePreferSwRenderer=false)
QRhi::Implementation rhiBackend() const
static QSGRhiSupport * instance()
bool remove(const T &value)
iterator insert(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
SurfaceType
The SurfaceType enum describes what type of surface this is.
static QUnifiedTimer * instance()
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Combined button and popup list for selecting options.
void qAddPostRoutine(QtCleanUpFunction p)
bool qFuzzyIsNull(qfloat16 f) noexcept
#define qCDebug(category,...)
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat GLfloat alpha
#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)
QT_BEGIN_NAMESPACE bool qsg_useConsistentTiming()
#define qPrintable(string)
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_TRACE_SCOPE(x,...)
#define Q_TRACE_POINT(provider, tracepoint,...)
QElapsedTimer timeBetweenRenders