summaryrefslogtreecommitdiffstats
path: root/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp')
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp98
1 files changed, 82 insertions, 16 deletions
diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
index 0c52c23fe..c8819ba1f 100644
--- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
@@ -4,6 +4,7 @@
#include "waylandeglclientbufferintegration_p.h"
#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtOpenGL/QOpenGLTexture>
#include <QtGui/QGuiApplication>
@@ -126,7 +127,11 @@ struct BufferState
EGLint egl_format = EGL_TEXTURE_RGBA;
QVarLengthArray<EGLImageKHR, 3> egl_images;
- 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 = true;
@@ -143,17 +148,15 @@ public:
void initEglTexture(WaylandEglClientBuffer *buffer, EGLint format);
bool ensureContext();
bool initEglStream(WaylandEglClientBuffer *buffer, struct ::wl_resource *bufferHandle);
+ void setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane);
void handleEglstreamTexture(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle);
void registerBuffer(struct ::wl_resource *buffer, BufferState state);
- void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; }
- void deleteOrphanedTextures();
EGLDisplay egl_display = EGL_NO_DISPLAY;
bool display_bound = false;
::wl_display *wlDisplay = nullptr;
QOffscreenSurface *offscreenSurface = nullptr;
QOpenGLContext *localContext = nullptr;
- QList<QOpenGLTexture *> orphanedTextures;
PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display = nullptr;
PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display = nullptr;
@@ -254,6 +257,8 @@ void WaylandEglClientBufferIntegrationPrivate::initEglTexture(WaylandEglClientBu
}
state.egl_images << image;
+
+ QMutexLocker locker(&state.texturesLock);
state.textures[i] = nullptr;
}
}
@@ -280,6 +285,50 @@ bool WaylandEglClientBufferIntegrationPrivate::ensureContext()
return localContextNeeded;
}
+
+void WaylandEglClientBufferIntegrationPrivate::setupBufferAndCleanup(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
+ << "(egl) 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 WaylandEglClientBufferIntegrationPrivate::initEglStream(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle)
{
BufferState &state = *buffer->d;
@@ -313,7 +362,11 @@ bool WaylandEglClientBufferIntegrationPrivate::initEglStream(WaylandEglClientBuf
auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES));
texture->create();
- state.textures[0] = texture; // TODO: support multiple planes for the streaming case
+ setupBufferAndCleanup(buffer->d, texture, 0);
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << " NEW texture! It's pointer and ctx pointer: "
+ << (void*)state.textures[0] << "; " << (void*)state.texturesContext[0];
texture->bind();
@@ -357,13 +410,6 @@ void WaylandEglClientBufferIntegrationPrivate::handleEglstreamTexture(WaylandEgl
localContext->doneCurrent();
}
-void WaylandEglClientBufferIntegrationPrivate::deleteOrphanedTextures()
-{
- Q_ASSERT(QOpenGLContext::currentContext());
- qDeleteAll(orphanedTextures);
- orphanedTextures.clear();
-}
-
WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration()
: d_ptr(new WaylandEglClientBufferIntegrationPrivate)
{
@@ -479,9 +525,29 @@ WaylandEglClientBuffer::~WaylandEglClientBuffer()
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();
+
+ QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(
+ 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;
}
@@ -524,7 +590,7 @@ QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane)
{
auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
// At this point we should have a valid OpenGL context, so it's safe to destroy textures
- p->deleteOrphanedTextures();
+ QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
if (!m_buffer)
return nullptr;
@@ -540,7 +606,7 @@ QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane)
texture->setFormat(openGLFormatFromEglFormat(d->egl_format));
texture->setSize(d->size.width(), d->size.height());
texture->create();
- d->textures[plane] = texture;
+ p->setupBufferAndCleanup(this->d, texture, plane);
}
if (m_textureDirty) {