summaryrefslogtreecommitdiffstats
path: root/src/compositor/hardware_integration/qwltextureorphanage.cpp
blob: c1ff86977f11d0e70d7c679316a0b5c0ca321dc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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,
            [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);

        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)
{
    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());

    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"