aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgcontext.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2023-01-25 19:47:17 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2023-02-08 20:14:43 +0000
commitac5bbbe4aca5e1abef4972aeeba22c8c2f923705 (patch)
treea6356c88de77576327f25d95d3df76bd44f95049 /src/quick/scenegraph/qsgcontext.cpp
parent403f4117e2ec25cc339876102dd9a25abcf0f442 (diff)
Have a way to always use an elapsed time based animation driver
Set QSG_USE_SIMPLE_ANIMATION_DRIVER=1 to get an alternative animation driver. (applies when using the threaded render loop) This behaves like the fallback mode (TimerMode) of the other one: it advances based on whatever delta the QElapsedTimer reports. Thus there is no dependency on vsync-based throttling whatsoever, and a big chunk of the workaround infrastructure (such as needing to fall back to QTimer with multiple windows) is simply not needed. It should be evaluated going forward if this should become the default. For now, in order to avoid any surprises, it is only opt-in. Pick-to: 6.5 Task-number: QTBUG-84328 Change-Id: I8e466caa08ba5f0471d767b1600d198ba787d8e5 Reviewed-by: Janne Koskinen <janne.p.koskinen@qt.io> Reviewed-by: Robert Griebl <robert.griebl@qt.io> Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/quick/scenegraph/qsgcontext.cpp')
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp125
1 files changed, 110 insertions, 15 deletions
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index f56e9898c6..be7c934fd7 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -63,6 +63,10 @@ Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph")
// Timing inside the renderer base class
Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer")
+// Applicable for render loops that install their own animation driver, such as
+// the 'threaded' loop. This env.var. is documented in the scenegraph docs.
+DEFINE_BOOL_CONFIG_OPTION(useElapsedTimerBasedAnimationDriver, QSG_USE_SIMPLE_ANIMATION_DRIVER);
+
bool qsg_useConsistentTiming()
{
int use = -1;
@@ -76,21 +80,9 @@ bool qsg_useConsistentTiming()
class QSGAnimationDriver : public QAnimationDriver
{
- Q_OBJECT
public:
- enum Mode {
- VSyncMode,
- TimerMode
- };
-
QSGAnimationDriver(QObject *parent)
: QAnimationDriver(parent)
- , m_time(0)
- , m_vsync(0)
- , m_mode(VSyncMode)
- , m_lag(0)
- , m_bad(0)
- , m_good(0)
{
QScreen *screen = QGuiApplication::primaryScreen();
if (screen) {
@@ -103,6 +95,35 @@ public:
} else {
m_vsync = 16.67f;
}
+ }
+
+ float vsyncInterval() const { return m_vsync; }
+
+ virtual bool isVSyncDependent() const = 0;
+
+protected:
+ float m_vsync = 0;
+};
+
+// default as in default for the threaded render loop
+class QSGDefaultAnimationDriver : public QSGAnimationDriver
+{
+ Q_OBJECT
+public:
+ enum Mode {
+ VSyncMode,
+ TimerMode
+ };
+
+ QSGDefaultAnimationDriver(QObject *parent)
+ : QSGAnimationDriver(parent)
+ , m_time(0)
+ , m_mode(VSyncMode)
+ , m_lag(0)
+ , m_bad(0)
+ , m_good(0)
+ {
+ QScreen *screen = QGuiApplication::primaryScreen();
if (screen && !qsg_useConsistentTiming()) {
if (m_vsync <= 0)
m_mode = TimerMode;
@@ -192,10 +213,12 @@ public:
advanceAnimation();
}
- float vsyncInterval() const { return m_vsync; } // this should always return something sane, regardless of m_mode
+ bool isVSyncDependent() const override
+ {
+ return true;
+ }
double m_time;
- float m_vsync;
Mode m_mode;
QElapsedTimer m_timer;
QElapsedTimer m_wallTime;
@@ -204,6 +227,67 @@ public:
int m_good;
};
+// Advance based on QElapsedTimer. (so like the TimerMode of QSGDefaultAnimationDriver)
+// Does not depend on vsync-based throttling.
+//
+// NB this is not the same as not installing a QAnimationDriver: the built-in
+// approach in QtCore is to rely on 16 ms timer events which are potentially a
+// lot less accurate.
+//
+// This has the benefits of:
+// - not needing any of the infrastructure for falling back to a
+// QTimer when there are multiple windows,
+// - needing no heuristics trying determine if vsync-based throttling
+// is missing or broken,
+// - being compatible with any kind of temporal drifts in vsync throttling
+// which is reportedly happening in various environments and platforms
+// still,
+// - not being tied to the primary screen's refresh rate, i.e. this is
+// correct even if the window is on some secondary screen with a
+// different refresh rate,
+// - not having to worry about the potential effects of variable refresh
+// rate solutions,
+// - render thread animators work correctly regardless of vsync.
+//
+// On the downside, some animations might appear less smooth (compared to the
+// ideal single window case of QSGDefaultAnimationDriver).
+//
+class QSGElapsedTimerAnimationDriver : public QSGAnimationDriver
+{
+public:
+ QSGElapsedTimerAnimationDriver(QObject *parent)
+ : QSGAnimationDriver(parent)
+ {
+ qCDebug(QSG_LOG_INFO, "Animation Driver: using QElapsedTimer, thread %p %s",
+ QThread::currentThread(),
+ QThread::currentThread() == qGuiApp->thread() ? "(gui/main thread)" : "(render thread)");
+ }
+
+ void start() override
+ {
+ m_wallTime.restart();
+ QAnimationDriver::start();
+ }
+
+ qint64 elapsed() const override
+ {
+ return m_wallTime.elapsed();
+ }
+
+ void advance() override
+ {
+ advanceAnimation();
+ }
+
+ bool isVSyncDependent() const override
+ {
+ return false;
+ }
+
+private:
+ QElapsedTimer m_wallTime;
+};
+
/*!
\class QSGContext
@@ -270,7 +354,10 @@ QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *)
*/
QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
{
- return new QSGAnimationDriver(parent);
+ if (useElapsedTimerBasedAnimationDriver())
+ return new QSGElapsedTimerAnimationDriver(parent);
+
+ return new QSGDefaultAnimationDriver(parent);
}
/*!
@@ -282,6 +369,14 @@ float QSGContext::vsyncIntervalForAnimationDriver(QAnimationDriver *driver)
return static_cast<QSGAnimationDriver *>(driver)->vsyncInterval();
}
+/*!
+ \return true if \a driver relies on vsync-based throttling in some form.
+ */
+bool QSGContext::isVSyncDependent(QAnimationDriver *driver)
+{
+ return static_cast<QSGAnimationDriver *>(driver)->isVSyncDependent();
+}
+
QSize QSGContext::minimumFBOSize() const
{
return QSize(1, 1);