The dpy_gl_release_dmabuf callbacks in the GTK, SDL, egl-headless,
and spice backends call egl_dmabuf_release_texture(), which calls
glDeleteTextures(), without first making the owning GL context
current. This is reachable after another console's surface update
leaves EGL_NO_CONTEXT current (e.g. gd_egl_update clears the context
on return). The deletion then silently fails, leaking the GL texture
and its backing storage. With an unshared context current, a
coincident texture name could even be deleted from the wrong context.

Fix by making the appropriate GL context current in each backend's
release callback before calling egl_dmabuf_release_texture():

- GTK EGL: eglMakeCurrent with the VC's EGL context
- GTK GL Area: gtk_gl_area_make_current
- SDL: SDL_GL_MakeCurrent with the console's window context
- egl-headless: eglMakeCurrent with the render-node context
- spice: eglMakeCurrent with the render-node context

For GTK, the previously shared gd_gl_release_dmabuf is split into
backend-specific gd_egl_release_dmabuf and gd_gl_area_release_dmabuf,
matching the existing pattern where each backend manages its own
context.

Reviewed-by: Akihiko Odaki <[email protected]>
Signed-off-by: Marc-André Lureau <[email protected]>
---
 include/ui/gtk.h   |  5 +++++
 ui/egl-headless.c  |  2 ++
 ui/gtk-egl.c       | 12 ++++++++++++
 ui/gtk-gl-area.c   | 11 +++++++++++
 ui/gtk.c           | 13 ++++---------
 ui/sdl2-gl.c       |  1 +
 ui/spice-display.c |  2 ++
 7 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index b66b9ca5c519..6b62e9758813 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -163,6 +163,7 @@ extern bool gtk_use_gl_area;
 void gd_update_windowsize(VirtualConsole *vc);
 void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget);
 void gd_gl_wait_sync(VirtualConsole *vc, void *sync);
+void gd_release_dmabuf(VirtualConsole *vc, QemuDmaBuf *dmabuf);
 
 /* ui/gtk-egl.c */
 void gd_egl_init(VirtualConsole *vc);
@@ -190,6 +191,8 @@ void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl,
                           uint32_t hot_x, uint32_t hot_y);
 void gd_egl_cursor_position(DisplayChangeListener *dcl,
                             uint32_t pos_x, uint32_t pos_y);
+void gd_egl_release_dmabuf(DisplayChangeListener *dcl,
+                           QemuDmaBuf *dmabuf);
 void gd_egl_flush(DisplayChangeListener *dcl,
                   uint32_t x, uint32_t y, uint32_t w, uint32_t h);
 void *gd_egl_scanout_flush(DisplayChangeListener *dcl,
@@ -221,6 +224,8 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
                                 uint32_t x, uint32_t y,
                                 uint32_t w, uint32_t h,
                                 void *d3d_tex2d);
+void gd_gl_area_release_dmabuf(DisplayChangeListener *dcl,
+                               QemuDmaBuf *dmabuf);
 void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);
 void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
                               uint32_t x, uint32_t y, uint32_t w, uint32_t h);
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index ba27efcf4c3e..ffe7b30f919b 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -126,6 +126,8 @@ static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
 static void egl_release_dmabuf(DisplayChangeListener *dcl,
                                QemuDmaBuf *dmabuf)
 {
+    eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE,
+                   EGL_NO_SURFACE, qemu_egl_rn_ctx);
     egl_dmabuf_release_texture(dmabuf);
 }
 
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 8623181336e9..d595916476d9 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -426,6 +426,18 @@ void gtk_egl_init(DisplayGLMode mode)
     display_opengl = 1;
 }
 
+void gd_egl_release_dmabuf(DisplayChangeListener *dcl,
+                           QemuDmaBuf *dmabuf)
+{
+#ifdef CONFIG_GBM
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                   vc->gfx.esurface, vc->gfx.ectx);
+    gd_release_dmabuf(vc, dmabuf);
+#endif
+}
+
 int gd_egl_make_current(DisplayGLCtx *dgc,
                         QEMUGLContext ctx)
 {
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 45c0c8c81a11..effd88f28721 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -360,6 +360,17 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
 #endif
 }
 
+void gd_gl_area_release_dmabuf(DisplayChangeListener *dcl,
+                               QemuDmaBuf *dmabuf)
+{
+#ifdef CONFIG_GBM
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+    gd_release_dmabuf(vc, dmabuf);
+#endif
+}
+
 void gtk_gl_area_init(void)
 {
     display_opengl = 1;
diff --git a/ui/gtk.c b/ui/gtk.c
index 55e45e8445bc..c615d35451b6 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -584,21 +584,16 @@ static bool gd_has_dmabuf(DisplayChangeListener *dcl)
     return vc->gfx.has_dmabuf;
 }
 
-static void gd_gl_release_dmabuf(DisplayChangeListener *dcl,
-                                 QemuDmaBuf *dmabuf)
-{
 #ifdef CONFIG_GBM
-    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
-
+void gd_release_dmabuf(VirtualConsole *vc, QemuDmaBuf *dmabuf)
+{
     egl_dmabuf_release_texture(dmabuf);
     if (vc->gfx.guest_fb.dmabuf == dmabuf) {
         vc->gfx.guest_fb.dmabuf = NULL;
         vc->gfx.draw_submitted = false;
     }
-#endif
 }
 
-#ifdef CONFIG_GBM
 static void gd_gl_fence_cb(void *vcon)
 {
     VirtualConsole *vc = vcon;
@@ -639,7 +634,7 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {
     .dpy_gl_scanout_disable  = gd_gl_area_scanout_disable,
     .dpy_gl_update           = gd_gl_area_scanout_flush,
     .dpy_gl_scanout_dmabuf   = gd_gl_area_scanout_dmabuf,
-    .dpy_gl_release_dmabuf   = gd_gl_release_dmabuf,
+    .dpy_gl_release_dmabuf   = gd_gl_area_release_dmabuf,
     .dpy_has_dmabuf          = gd_has_dmabuf,
 };
 
@@ -673,7 +668,7 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
     .dpy_gl_cursor_dmabuf    = gd_egl_cursor_dmabuf,
     .dpy_gl_cursor_position  = gd_egl_cursor_position,
     .dpy_gl_update           = gd_egl_flush,
-    .dpy_gl_release_dmabuf   = gd_gl_release_dmabuf,
+    .dpy_gl_release_dmabuf   = gd_egl_release_dmabuf,
     .dpy_has_dmabuf          = gd_has_dmabuf,
 };
 
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index 46eff768c968..3a5aa09618ca 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -288,6 +288,7 @@ void sdl2_gl_release_dmabuf(DisplayChangeListener *dcl,
 {
     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 
+    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
     egl_dmabuf_release_texture(dmabuf);
     if (scon->guest_fb.dmabuf == dmabuf) {
         scon->guest_fb.dmabuf = NULL;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 75c7df7bb5e0..22cd1e266caa 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -1176,6 +1176,8 @@ static void 
qemu_spice_gl_release_dmabuf(DisplayChangeListener *dcl,
         ssd->guest_dmabuf = NULL;
         ssd->guest_dmabuf_refresh = false;
     }
+    eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE,
+                   EGL_NO_SURFACE, qemu_egl_rn_ctx);
     egl_dmabuf_release_texture(dmabuf);
 }
 

-- 
2.55.0.543.g5ebe2ebe4ea8


Reply via email to