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
88#ifdef ENABLE_DEFAULT_BACKEND
98#ifdef ENABLE_DEFAULT_BACKEND
111#ifdef ENABLE_DEFAULT_BACKEND
179#ifdef ENABLE_DEFAULT_BACKEND
216 if (qmlNoThreadedRenderer())
218 else if (qmlForceThreadedRenderer())
223 if (loopName ==
"windows") {
224 qWarning(
"The 'windows' render loop is no longer supported. Using 'basic' instead.");
226 }
else if (loopName ==
"basic") {
228 }
else if (loopName ==
"threaded") {
236 qCDebug(QSG_LOG_INFO,
"threaded render loop");
241 qCDebug(QSG_LOG_INFO,
"basic render loop");
265 &untranslatedMessage);
269 const bool signalEmitted =
274 MessageBox(0, (LPCTSTR) translatedMessage.
utf16(),
276 MB_OK | MB_ICONERROR);
283#ifdef ENABLE_DEFAULT_BACKEND
288 qCDebug(QSG_LOG_INFO,
"using fixed animation steps");
315 it->updatePending =
false;
331 data.rhi->makeThreadLocalNativeContextCurrent();
340 qWarning(
"QSGGuiThreadRenderLoop cleanup with QQuickWindow %p swapchain %p still alive, this should not happen.",
345 d->cleanupNodesOnShutdown();
347#if QT_CONFIG(quick_shadereffect)
352 data.rc->invalidate();
361 d->animationController.reset();
371 qWarning(
"Graphics device lost, cleaning up scenegraph and releasing RHIs");
374 if (!
it->rhi || !
it->rhi->isDeviceLost())
380 it->rc->invalidate();
383 it->rhiDeviceLost =
true;
405 switch (
event->type()) {
426 bool ok =
data.rhi !=
nullptr;
444 data.rhiDeviceLost =
false;
449 data.rhi->makeThreadLocalNativeContextCurrent();
464 if (!
data.rhiDeviceLost) {
465 data.rhiDoomed =
true;
497 qCDebug(QSG_LOG_INFO,
"Swap interval is 0, attempting to disable vsync when presenting.");
503 if (depthBufferEnabled) {
512 qCDebug(QSG_LOG_INFO,
"MSAA sample count for the swapchain is %d. Alpha channel requested = %s",
519 window->installEventFilter(
this);
527 qWarning(
"No QSGRenderContext for window %p, this should not happen",
window);
540 bool alsoSwap =
data.updatePending;
541 data.updatePending =
false;
553 bool lastDirtyWindow =
true;
555 if (
it->updatePending) {
556 lastDirtyWindow =
false;
566 QSize effectiveOutputSize;
572 if (effectiveOutputSize.
isEmpty())
578 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
579 const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
582 Q_TRACE(QSG_polishItems_entry);
594 QQuickProfiler::SceneGraphRenderLoopFrame,
595 QQuickProfiler::SceneGraphPolishPolish);
609 qCDebug(QSG_LOG_RENDERLOOP,
"just became exposed");
625 qCDebug(QSG_LOG_RENDERLOOP) <<
"rhi swapchain size" << effectiveOutputSize;
627 qWarning(
"Failed to build or resize swapchain");
650 data.rhi->makeThreadLocalNativeContextCurrent();
661 QQuickProfiler::SceneGraphRenderLoopSync);
670 QQuickProfiler::SceneGraphRenderLoopRender);
673 const bool needsPresent = alsoSwap &&
window->isVisible();
674 double lastCompletedGpuTime = 0;
676 QRhi::EndFrameFlags
flags;
699 QQuickProfiler::SceneGraphRenderLoopSwap);
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",
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()));
712 qCDebug(QSG_LOG_TIME_RENDERLOOP,
"[window %p][gui thread] syncAndRender: last retrieved GPU frame time was %.4f ms",
714 lastCompletedGpuTime * 1000.0);
719 if (
data.updatePending)
747 winDataIt->updatePending =
true;
777 image.setDevicePixelRatio(
window->effectiveDevicePixelRatio());
791 winDataIt->updatePending =
true;
823 emit d->context->releaseCachedResourcesRequested();
825 d->renderer->releaseCachedResources();
826#if QT_CONFIG(quick_shadereffect)
840#include "qsgrenderloop.moc"
841#include "moc_qsgrenderloop_p.cpp"
QString applicationName
the name of this application
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
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 isTimestampsEnabled() const
QRhiRenderPassDescriptor * rpDescForSwapchain
bool emitError(QQuickWindow::SceneGraphError error, const QString &msg)
QQuickGraphicsConfiguration graphicsConfig
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGRenderContext * context
uint swapchainJustBecameRenderable
QRhiRenderBuffer * depthStencilForSwapchain
static void rhiCreationFailureMessage(const QString &backendName, QString *translatedMessage, QString *untranslatedMessage)
void cleanupNodesOnShutdown()
QQuickDeliveryAgentPrivate * deliveryAgentPrivate() const
QRhiSwapChain * swapchain
uint hasRenderableSwapchain
QSGRenderLoop * windowManager
bool isRenderable() const
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
double lastCompletedGpuTime()
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.
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
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 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
bool remove(const T &value)
iterator insert(const T &value)
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
\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()
void setConsistentTiming(bool consistent)
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,...)
QSize initialSurfacePixelSize
QElapsedTimer timeBetweenRenders