summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Klokkhammer Helsing <johan.helsing@qt.io>2018-03-22 15:44:20 +0100
committerJohan Helsing <johan.helsing@qt.io>2018-04-27 10:17:45 +0000
commit51472970ce519fb39f492238b879d67ad9505f28 (patch)
treedc58b8865c5992a160481650952db3ff753f68e4
parentf8a16e0edb11d3acc7f2448a4bcd0eb9606b39dc (diff)
Compositor API: Don't leak OpenGL textures when running multi-threaded
If a client destroyed buffers, they would not get deleted because the event would be handled on the GUI thread without a valid OpenGL context. I.e: you would see the following output: QOpenGLTexturePrivate::destroy() called without a current context. Texture has not been destroyed Work around it by keeping a list of buffers that have been orphaned and delete them whenever we have a valid OpenGL context. Change-Id: I31c7c4cff179bd68cd954714b2a8e3e2a74675b2 Reviewed-by: Dominik Holland <dominik.holland@pelagicore.com> Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
index 6de664564..2cadf8503 100644
--- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
@@ -180,12 +180,15 @@ public:
bool initEglStream(WaylandEglClientBuffer *buffer, struct ::wl_resource *bufferHandle);
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 valid = false;
bool display_bound = false;
QOffscreenSurface *offscreenSurface = nullptr;
QOpenGLContext *localContext = nullptr;
+ QVector<QOpenGLTexture *> orphanedTextures;
PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display = nullptr;
PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display = nullptr;
@@ -376,6 +379,13 @@ void WaylandEglClientBufferIntegrationPrivate::handleEglstreamTexture(WaylandEgl
localContext->doneCurrent();
}
+void WaylandEglClientBufferIntegrationPrivate::deleteOrphanedTextures()
+{
+ Q_ASSERT(QOpenGLContext::currentContext());
+ qDeleteAll(orphanedTextures);
+ orphanedTextures.clear();
+}
+
WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration()
: d_ptr(new WaylandEglClientBufferIntegrationPrivate)
{
@@ -484,7 +494,7 @@ WaylandEglClientBuffer::~WaylandEglClientBuffer()
p->funcs->destroy_stream(p->egl_display, d->egl_stream);
for (auto *texture : d->textures)
- delete texture;
+ p->deleteGLTextureWhenPossible(texture);
}
delete d;
}
@@ -526,6 +536,10 @@ QWaylandBufferRef::BufferFormatEgl WaylandEglClientBuffer::bufferFormatEgl() con
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();
+
if (!m_buffer)
return nullptr;
@@ -533,7 +547,6 @@ QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane)
if (d->eglMode == BufferState::ModeEGLStream)
return texture; // EGLStreams texture is maintained by handle_eglstream_texture()
- auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
const auto target = static_cast<QOpenGLTexture::Target>(d->egl_format == EGL_TEXTURE_EXTERNAL_WL ? GL_TEXTURE_EXTERNAL_OES
: GL_TEXTURE_2D);
if (!texture) {