summaryrefslogtreecommitdiff
path: root/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp')
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp136
1 files changed, 131 insertions, 5 deletions
diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
index f43bfb09..2e2b2829 100644
--- a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
@@ -9,6 +9,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOffscreenSurface>
+#include <QtCore/QMutexLocker>
#include <QtGui/private/qeglstreamconvenience_p.h>
#include <qpa/qplatformnativeinterface.h>
@@ -109,7 +110,11 @@ struct BufferState
BufferState() = default;
EGLint egl_format = EGL_TEXTURE_EXTERNAL_WL;
- QOpenGLTexture *textures[3] = {};
+ QOpenGLTexture *textures[3] = {nullptr, nullptr, nullptr};
+ QOpenGLContext *texturesContext[3] = {nullptr, nullptr, nullptr};
+ QMetaObject::Connection texturesAboutToBeDestroyedConnection[3] = {QMetaObject::Connection(), QMetaObject::Connection(), QMetaObject::Connection()};
+ QMutex texturesLock;
+
EGLStreamKHR egl_stream = EGL_NO_STREAM_KHR;
bool isYInverted = false;
@@ -124,15 +129,19 @@ public:
bool ensureContext();
bool initEglStream(WaylandEglStreamClientBuffer *buffer, struct ::wl_resource *bufferHandle);
void handleEglstreamTexture(WaylandEglStreamClientBuffer *buffer);
- void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; }
+ void deleteGLTextureWhenPossible(QOpenGLTexture *texture, QOpenGLContext *ctx);
void deleteOrphanedTextures();
+ void deleteSpecificOrphanedTexture(QOpenGLTexture *texture);
EGLDisplay egl_display = EGL_NO_DISPLAY;
bool display_bound = false;
::wl_display *wlDisplay = nullptr;
QOffscreenSurface *offscreenSurface = nullptr;
QOpenGLContext *localContext = nullptr;
+
+ QMutex orphanedTexturesLock;
QList<QOpenGLTexture *> orphanedTextures;
+ QList<QMetaObject::Connection> orphanedTexturesAboutToBeDestroyedConnection;
WaylandEglStreamController *eglStreamController = nullptr;
@@ -150,13 +159,71 @@ public:
bool WaylandEglStreamClientBufferIntegrationPrivate::shuttingDown = false;
+
+void WaylandEglStreamClientBufferIntegrationPrivate::deleteGLTextureWhenPossible(QOpenGLTexture *texture, QOpenGLContext *ctx) {
+
+ QMutexLocker locker(&orphanedTexturesLock);
+
+ Q_ASSERT(orphanedTextures.size() == orphanedTexturesAboutToBeDestroyedConnection.size());
+
+ orphanedTextures << texture;
+ orphanedTexturesAboutToBeDestroyedConnection << QObject::connect(ctx, &QOpenGLContext::aboutToBeDestroyed,
+ ctx, [this, texture]() {
+ this->deleteSpecificOrphanedTexture(texture);
+ }, Qt::DirectConnection);
+}
+
void WaylandEglStreamClientBufferIntegrationPrivate::deleteOrphanedTextures()
{
Q_ASSERT(QOpenGLContext::currentContext());
+
+ QMutexLocker locker(&orphanedTexturesLock);
+
+ for (int i=0; i < orphanedTextures.size(); i++) {
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO << " about to delete a texture: "
+ << (void*)orphanedTextures[i];
+ }
+
qDeleteAll(orphanedTextures);
+
+ for (QMetaObject::Connection con : orphanedTexturesAboutToBeDestroyedConnection)
+ QObject::disconnect(con);
+
+ orphanedTexturesAboutToBeDestroyedConnection.clear();
orphanedTextures.clear();
}
+void WaylandEglStreamClientBufferIntegrationPrivate::deleteSpecificOrphanedTexture(QOpenGLTexture *texture)
+{
+ Q_ASSERT(orphanedTextures.size() == orphanedTexturesAboutToBeDestroyedConnection.size());
+
+ QMutexLocker locker(&orphanedTexturesLock);
+
+ // In this case, deleteOrphanedTextures was called while we entered (see lock!) this function!
+ if (orphanedTextures.length()==0) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "Looks like deleteOrphanedTextures() and this function where called simultaneously!"
+ << "This might cause issues!";
+ return;
+ }
+
+ int i = orphanedTextures.indexOf(texture);
+ Q_ASSERT(i!=-1); // If it isn't empty (see above if), then it should be guaranteed to still contain this texture
+
+ orphanedTextures.removeAt(i);
+ QMetaObject::Connection con = orphanedTexturesAboutToBeDestroyedConnection.takeAt(i);
+
+ QObject::disconnect(con);
+ delete texture;
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
+ << "Pointer (now dead) was:" << (void*)texture;
+}
+
bool WaylandEglStreamClientBufferIntegrationPrivate::ensureContext()
{
bool localContextNeeded = false;
@@ -180,6 +247,49 @@ bool WaylandEglStreamClientBufferIntegrationPrivate::ensureContext()
}
+void setupWaylandEglClientBufferWithTextureContextAndAboutToBeDestroyedConnection(BufferState *bs, QOpenGLTexture *texture, int plane)
+{
+ QMutexLocker locker(&bs->texturesLock);
+
+ bs->textures[plane] = texture;
+ bs->texturesContext[plane] = QOpenGLContext::currentContext();
+
+ Q_ASSERT(bs->texturesContext[plane] != nullptr);
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "(eglstream) creating a cleanup-lambda for QOpenGLContext::aboutToBeDestroyed!"
+ << ", texture: " << bs->textures[plane]
+ << ", ctx: " << (void*)bs->texturesContext[plane];
+
+ bs->texturesAboutToBeDestroyedConnection[plane] =
+ QObject::connect(bs->texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
+ bs->texturesContext[plane], [bs, plane]() {
+
+ QMutexLocker locker(&bs->texturesLock);
+
+ // See above lock - there is a chance that this has already been removed from textures[plane]!
+ // Furthermore, we can trust that all the rest (e.g. disconnect) has also been properly executed!
+ if (bs->textures[plane] == nullptr)
+ return;
+
+ delete bs->textures[plane];
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
+ << "Pointer (now dead) was:" << (void*)(bs->textures[plane])
+ << " Associated context (about to die too) is: " << (void*)(bs->texturesContext[plane]);
+
+ bs->textures[plane] = nullptr;
+ bs->texturesContext[plane] = nullptr;
+
+ QObject::disconnect(bs->texturesAboutToBeDestroyedConnection[plane]);
+ bs->texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
+
+ }, Qt::DirectConnection);
+}
+
bool WaylandEglStreamClientBufferIntegrationPrivate::initEglStream(WaylandEglStreamClientBuffer *buffer, wl_resource *bufferHandle)
{
BufferState &state = *buffer->d;
@@ -210,7 +320,7 @@ bool WaylandEglStreamClientBufferIntegrationPrivate::initEglStream(WaylandEglStr
auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES));
texture->create();
- state.textures[0] = texture; // TODO: support multiple planes
+ setupWaylandEglClientBufferWithTextureContextAndAboutToBeDestroyedConnection(buffer->d, texture, 0);
texture->bind();
@@ -360,9 +470,25 @@ WaylandEglStreamClientBuffer::~WaylandEglStreamClientBuffer()
if (d->egl_stream)
p->funcs->destroy_stream(p->egl_display, d->egl_stream);
- for (auto *texture : d->textures)
- p->deleteGLTextureWhenPossible(texture);
+ QMutexLocker locker(&d->texturesLock);
+
+ for (int i=0; i<3; i++) {
+ if (d->textures[i] != nullptr) {
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO << " handing over texture!"
+ << (void*)d->textures[i] << "; " << (void*)d->texturesContext[i]
+ << " ... current context might be the same: " << QOpenGLContext::currentContext();
+
+ p->deleteGLTextureWhenPossible(d->textures[i], d->texturesContext[i]);
+ d->textures[i] = nullptr; // in case the aboutToBeDestroyed lambda is called while we where here
+ d->texturesContext[i] = nullptr;
+ QObject::disconnect(d->texturesAboutToBeDestroyedConnection[i]);
+ d->texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
+ }
+ }
}
+
delete d;
}