diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2018-03-22 15:44:20 +0100 |
---|---|---|
committer | Johan Helsing <johan.helsing@qt.io> | 2018-04-27 10:17:45 +0000 |
commit | 51472970ce519fb39f492238b879d67ad9505f28 (patch) | |
tree | dc58b8865c5992a160481650952db3ff753f68e4 | |
parent | f8a16e0edb11d3acc7f2448a4bcd0eb9606b39dc (diff) | |
download | qtwayland-51472970ce519fb39f492238b879d67ad9505f28.tar.gz |
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.cpp | 17 |
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 6de66456..2cadf850 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) { |