Revision control
Copy as Markdown
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#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,
[this, ctx]() { this->onContextAboutToBeDestroyed(ctx); },
Qt::ConnectionType(Qt::DirectConnection));
}
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);
const auto contexts = m_orphanedTextures.keys();
for (QOpenGLContext *aCtx : contexts) {
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)
{
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!
// If not (e.g.: someone changes something in/around this class),
// then in a debug-build we will fail below:
Q_ASSERT(!m_containerLock.tryLock());
const 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"