aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgcontext.cpp')
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp285
1 files changed, 225 insertions, 60 deletions
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index d9ed25c099..01e0707556 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/private/qsgtexture_p.h>
-#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtQuick/private/qsgrenderer_p.h>
+#include <QtQuick/private/qquickpixmap_p.h>
#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuick/private/qsginternaltextnode_p.h>
#include <QGuiApplication>
#include <QScreen>
@@ -98,6 +64,13 @@ 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")
+// Leak checks
+Q_LOGGING_CATEGORY(lcQsgLeak, "qt.scenegraph.leaks")
+
+// 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;
@@ -111,6 +84,34 @@ bool qsg_useConsistentTiming()
class QSGAnimationDriver : public QAnimationDriver
{
+public:
+ QSGAnimationDriver(QObject *parent)
+ : QAnimationDriver(parent)
+ {
+ QScreen *screen = QGuiApplication::primaryScreen();
+ if (screen) {
+ qreal refreshRate = screen->refreshRate();
+ // To work around that some platforms wrongfully return 0 or something
+ // bogus for the refresh rate.
+ if (refreshRate < 1)
+ refreshRate = 60;
+ m_vsync = 1000.0f / float(refreshRate);
+ } 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 {
@@ -118,10 +119,9 @@ public:
TimerMode
};
- QSGAnimationDriver(QObject *parent)
- : QAnimationDriver(parent)
+ QSGDefaultAnimationDriver(QObject *parent)
+ : QSGAnimationDriver(parent)
, m_time(0)
- , m_vsync(0)
, m_mode(VSyncMode)
, m_lag(0)
, m_bad(0)
@@ -129,7 +129,6 @@ public:
{
QScreen *screen = QGuiApplication::primaryScreen();
if (screen && !qsg_useConsistentTiming()) {
- m_vsync = 1000.0 / screen->refreshRate();
if (m_vsync <= 0)
m_mode = TimerMode;
} else {
@@ -180,7 +179,7 @@ public:
m_time += m_vsync;
- if (delta > m_vsync * 1.25) {
+ if (delta > m_vsync * 1.25f) {
m_lag += (delta / m_vsync);
m_bad++;
// We tolerate one bad frame without resorting to timer based. This is
@@ -197,7 +196,7 @@ public:
}
} else {
- if (delta < 1.25 * m_vsync) {
+ if (delta < 1.25f * m_vsync) {
++m_good;
} else {
m_good = 0;
@@ -218,22 +217,101 @@ public:
advanceAnimation();
}
+ bool isVSyncDependent() const override
+ {
+ return true;
+ }
+
double m_time;
- double m_vsync;
Mode m_mode;
QElapsedTimer m_timer;
QElapsedTimer m_wallTime;
- double m_lag;
+ float m_lag;
int m_bad;
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;
+};
+
+QSGRenderContext::FontKey::FontKey(const QRawFont &font, int quality)
+{
+ QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
+ if (fe != nullptr)
+ faceId = fe->faceId();
+ style = font.style();
+ weight = font.weight();
+ renderTypeQuality = quality;
+ if (faceId.filename.isEmpty()) {
+ familyName = font.familyName();
+ styleName = font.styleName();
+ }
+}
+
/*!
\class QSGContext
\brief The QSGContext holds the scene graph entry points for one QML engine.
- The context is not ready for use until it has a QOpenGLContext. Once that happens,
+ The context is not ready for use until it has a QRhi. Once that happens,
the scene graph population can start.
\internal
@@ -269,10 +347,20 @@ QSGInternalRectangleNode *QSGContext::createInternalRectangleNode(const QRectF &
return node;
}
+QSGInternalTextNode *QSGContext::createInternalTextNode(QSGRenderContext *renderContext)
+{
+ return new QSGInternalTextNode(renderContext);
+}
+
+QSGTextNode *QSGContext::createTextNode(QSGRenderContext *renderContext)
+{
+ return createInternalTextNode(renderContext);
+}
+
/*!
Creates a new shader effect helper instance. This function is called on the
- gui thread, unlike the others. This is necessary in order to provide
- adaptable, backend-specific shader effect functionality to the gui thread too.
+ GUI thread, unlike the others. This is necessary in order to provide
+ adaptable, backend-specific shader effect functionality to the GUI thread too.
*/
QSGGuiThreadShaderEffectManager *QSGContext::createGuiThreadShaderEffectManager()
{
@@ -284,7 +372,7 @@ QSGGuiThreadShaderEffectManager *QSGContext::createGuiThreadShaderEffectManager(
valid as long as the backend does not claim SupportsShaderEffectNode or
ignoring ShaderEffect elements is acceptable.
*/
-QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *, QSGGuiThreadShaderEffectManager *)
+QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *)
{
return nullptr;
}
@@ -294,7 +382,27 @@ QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *, QSGG
*/
QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
{
- return new QSGAnimationDriver(parent);
+ if (useElapsedTimerBasedAnimationDriver())
+ return new QSGElapsedTimerAnimationDriver(parent);
+
+ return new QSGDefaultAnimationDriver(parent);
+}
+
+/*!
+ \return the vsync rate (such as, 16.68 ms or similar), if applicable, for
+ the \a driver that was created by createAnimationDriver().
+ */
+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
@@ -305,7 +413,7 @@ QSize QSGContext::minimumFBOSize() const
/*!
Returns a pointer to the (presumably) global renderer interface.
- \note This function may be called on the gui thread in order to get access
+ \note This function may be called on the GUI thread in order to get access
to QSGRendererInterface::graphicsApi() and other getters.
\note it is expected that the simple queries (graphicsApi, shaderType,
@@ -332,15 +440,40 @@ QSGRenderContext::~QSGRenderContext()
{
}
-void QSGRenderContext::initialize(void *context)
+void QSGRenderContext::initialize(const InitParams *params)
{
- Q_UNUSED(context);
+ Q_UNUSED(params);
}
void QSGRenderContext::invalidate()
{
}
+void QSGRenderContext::prepareSync(qreal devicePixelRatio,
+ QRhiCommandBuffer *cb,
+ const QQuickGraphicsConfiguration &config)
+{
+ Q_UNUSED(devicePixelRatio);
+ Q_UNUSED(cb);
+ Q_UNUSED(config);
+}
+
+void QSGRenderContext::beginNextFrame(QSGRenderer *renderer, const QSGRenderTarget &renderTarget,
+ RenderPassCallback mainPassRecordingStart,
+ RenderPassCallback mainPassRecordingEnd,
+ void *callbackUserData)
+{
+ renderer->setRenderTarget(renderTarget);
+ Q_UNUSED(mainPassRecordingStart);
+ Q_UNUSED(mainPassRecordingEnd);
+ Q_UNUSED(callbackUserData);
+}
+
+void QSGRenderContext::endNextFrame(QSGRenderer *renderer)
+{
+ Q_UNUSED(renderer);
+}
+
void QSGRenderContext::endSync()
{
qDeleteAll(m_texturesToDelete);
@@ -348,18 +481,50 @@ void QSGRenderContext::endSync()
}
/*!
+ Do necessary preprocessing before the frame
+*/
+void QSGRenderContext::preprocess()
+{
+}
+
+/*!
+ Factory function for curve atlases that can be used to provide geometry for the curve
+ renderer for a given font.
+*/
+QSGCurveGlyphAtlas *QSGRenderContext::curveGlyphAtlas(const QRawFont &font)
+{
+ Q_UNUSED(font);
+ return nullptr;
+}
+
+/*!
Factory function for scene graph backends of the distance-field glyph cache.
*/
-QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &)
+QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &, int)
{
return nullptr;
}
+void QSGRenderContext::invalidateGlyphCaches()
+{
+
+}
void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
{
engine->ref.ref();
- m_fontEnginesToClean << engine;
+ m_fontEnginesToClean[engine]++;
+}
+
+void QSGRenderContext::unregisterFontengineForCleanup(QFontEngine *engine)
+{
+ m_fontEnginesToClean[engine]--;
+ Q_ASSERT(m_fontEnginesToClean.value(engine) >= 0);
+}
+
+QRhi *QSGRenderContext::rhi() const
+{
+ return nullptr;
}
/*!
@@ -393,7 +558,7 @@ QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, Q
void QSGRenderContext::textureFactoryDestroyed(QObject *o)
{
m_mutex.lock();
- m_texturesToDelete << m_textures.take(static_cast<QQuickTextureFactory *>(o));
+ m_texturesToDelete << m_textures.take(o);
m_mutex.unlock();
}
@@ -411,7 +576,7 @@ QSGTexture *QSGRenderContext::compressedTextureForFactory(const QSGCompressedTex
return nullptr;
}
+QT_END_NAMESPACE
+
#include "qsgcontext.moc"
#include "moc_qsgcontext_p.cpp"
-
-QT_END_NAMESPACE