diff options
author | Thomas Senyk <thomas.senyk@qt.io> | 2023-07-19 10:46:14 +0200 |
---|---|---|
committer | Thomas Senyk <thomas.senyk@qt.io> | 2023-09-18 10:48:55 +0200 |
commit | 2cea2d8520af4f3647f2e7aa7444b68c9c1e51cf (patch) | |
tree | 58766e88de8b47f1f94a2d05092b0e5ef39adf0b /src/compositor/hardware_integration | |
parent | 9bd005620f49e62eadd8f94c02821bd85099d928 (diff) |
Reimplement orphaned texture handling
The previous implementation was a bit error prone
(there was a reproducable "dead pointer" issue)
and had duplicated code (dma, egl and eglstream share the same code).
The new implementation fixes both issues (and more):
- no more 'this' capture on a lambda where the 'this' isn't an object
and hence can go out of scope without the lambda knowing.
- no more duplicated code as we now have a singleton as our orphanage:
QWaylandTextureOrphanage
3 (dma, egl, eglstream) HW-integrations use this singleton
- the class itself as well as it's container are thread-safe
by the usage of QMutex/QMutexLocker.
This also includes the deletion code within the orphanage.
As the orphanes are 100% owned by the orphanage,
they are protected from double deletion.
- The cleanup due to QOpenGLContext::aboutToBeDestroyed is
now ctx specific, no more lamdba-per-texture.
Change-Id: I36e82fae796864319bed7ebdb5154e93dbe96394
Pick-to: 6.6
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Diffstat (limited to 'src/compositor/hardware_integration')
-rw-r--r-- | src/compositor/hardware_integration/qwltextureorphanage.cpp | 108 | ||||
-rw-r--r-- | src/compositor/hardware_integration/qwltextureorphanage_p.h | 64 |
2 files changed, 172 insertions, 0 deletions
diff --git a/src/compositor/hardware_integration/qwltextureorphanage.cpp b/src/compositor/hardware_integration/qwltextureorphanage.cpp new file mode 100644 index 000000000..c1337190a --- /dev/null +++ b/src/compositor/hardware_integration/qwltextureorphanage.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "qwltextureorphanage_p.h" + +#include <QOpenGLContext> +#include <QOpenGLTexture> +#include <QDebug> +#include <QtTypeTraits> +#include <QMutexLocker> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcWTO, "qt.waylandcompositor.orphanage") + +Q_GLOBAL_STATIC(QtWayland::QWaylandTextureOrphanage, inst) + +namespace QtWayland { + +QWaylandTextureOrphanage::~QWaylandTextureOrphanage() +{ + QMutexLocker locker(&m_containerLock); + if (!m_orphanedTextures.isEmpty()) { + qCWarning(qLcWTO) << Q_FUNC_INFO << "m_orphanedTextures container isn't empty! content:" + << m_orphanedTextures; + } +} + +QWaylandTextureOrphanage *QWaylandTextureOrphanage::instance() +{ + return inst; +} + +void QWaylandTextureOrphanage::admitTexture(QOpenGLTexture *tex, QOpenGLContext *ctx) +{ + qCDebug(qLcWTO) << Q_FUNC_INFO << "got a texture (" << (void *)tex + << ") ready to be deleted! It's ctx:" << ctx; + + { + QMutexLocker locker(&m_containerLock); + m_orphanedTextures.insert(ctx, tex); + } + + connect(ctx, &QOpenGLContext::aboutToBeDestroyed, this, + &QWaylandTextureOrphanage::onContextAboutToBeDestroyed, + Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection)); +} + +void QWaylandTextureOrphanage::deleteTextures() +{ + QOpenGLContext *cCtx = QOpenGLContext::currentContext(); + + if (cCtx == nullptr) { + qCWarning(qLcWTO) << Q_FUNC_INFO << "cannot delete textures without current OpenGL context"; + return; + } + + { + QMutexLocker locker(&m_containerLock); + + for (QOpenGLContext *aCtx : m_orphanedTextures.keys()) { + if (QOpenGLContext::areSharing(cCtx, aCtx)) { + + qCDebug(qLcWTO) << Q_FUNC_INFO << "currentContext (" << cCtx + << ") and ctx of orphane(s) (" << aCtx + << ") are shared! => deleteTexturesByContext"; + + deleteTexturesByContext(aCtx); + } + } + } +} + +void QWaylandTextureOrphanage::onContextAboutToBeDestroyed() +{ + QOpenGLContext *ctx = qobject_cast<QOpenGLContext *>(sender()); + Q_ASSERT(ctx != nullptr); + + qCDebug(qLcWTO) << Q_FUNC_INFO << " ctx (" << ctx + << ") fired aboutToBeDestroyed => deleteTexturesByContext(ctx)"; + + { + QMutexLocker locker(&m_containerLock); + deleteTexturesByContext(ctx); + } +} + +void QWaylandTextureOrphanage::deleteTexturesByContext(QOpenGLContext *ctx) +{ + // NOTE: We are (by class-internal design) locked (m_containerLock) + // when we enter this function! + // So in a debug-build we will fail below: + Q_ASSERT(!m_containerLock.tryLock()); + + QList<QOpenGLTexture *> texturesToDelete = m_orphanedTextures.values(ctx); + m_orphanedTextures.remove(ctx); + + for (QOpenGLTexture *tex : texturesToDelete) { + delete tex; + qCDebug(qLcWTO) << Q_FUNC_INFO << " texture (" << (void *)tex << ") got deleted"; + } +} + +} // namespace QtWayland + +QT_END_NAMESPACE + +#include "moc_qwltextureorphanage_p.cpp" diff --git a/src/compositor/hardware_integration/qwltextureorphanage_p.h b/src/compositor/hardware_integration/qwltextureorphanage_p.h new file mode 100644 index 000000000..d267043e4 --- /dev/null +++ b/src/compositor/hardware_integration/qwltextureorphanage_p.h @@ -0,0 +1,64 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef QWLTEXTUREORPHANAGE_P_H +#define QWLTEXTUREORPHANAGE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QObject> +#include <QMutex> +#include <QLoggingCategory> +#include <QtWaylandCompositor/qtwaylandcompositorglobal.h> + +QT_BEGIN_NAMESPACE + +class QOpenGLContext; +class QOpenGLTexture; + +Q_DECLARE_LOGGING_CATEGORY(qLcWTO) + +namespace QtWayland { + +class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextureOrphanage : public QObject +{ + Q_OBJECT + +public: + QWaylandTextureOrphanage(){}; + ~QWaylandTextureOrphanage(); + + static QWaylandTextureOrphanage *instance(); + + // texture that isn't needed anymore will be "take care of" (killed) appropriately + void admitTexture(QOpenGLTexture *tex, QOpenGLContext *ctx); + + // uses QOpenGLContext::currentContext to call deleteTexturesByContext on all shared ctx + void deleteTextures(); + +public slots: + // uses sender() to call deleteTexturesByContext + void onContextAboutToBeDestroyed(); + +private: + void deleteTexturesByContext(QOpenGLContext *ctx); + + // tracks all the orphanes that need to be deleted + QMultiHash<QOpenGLContext *, QOpenGLTexture *> m_orphanedTextures; + + QMutex m_containerLock; +}; + +} // namespace QtWayland + +QT_END_NAMESPACE +#endif |