ui/egl: implement display and EGL cleanup
Add egl_cleanup() to tear down the EGL render node context, GBM device, and EGL display. Add egl_headless_cleanup() to unregister listeners, destroy framebuffers, and free per-console state tracked via a new GPtrArray. Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260623-b4-ui-v4-19-4656aec3398d@redhat.com>
Marc-André Lureau committed
Jun 23, 2026 at 11:44 UTC
a3cf9b55bbdc23f1d5fb9a455eed7670e2e2e5bc
3 files changed
+51
include/ui/egl-helpers.h
+1
@@ -81,6 +81,7 @@ EGLContext qemu_egl_init_ctx(void);
81
bool qemu_egl_has_dmabuf(void);
82
83
bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp);
84
+void egl_cleanup(void);
85
86
const char *qemu_egl_get_error_string(void);
87
ui/egl-headless.c
+31
@@ -9,6 +9,7 @@
9
10
typedef struct egl_dpy {
11
DisplayChangeListener dcl;
12
+ DisplayGLCtx *ctx;
13
DisplaySurface *ds;
14
QemuGLShader *gls;
15
egl_fb guest_fb;
@@ -19,6 +20,8 @@ typedef struct egl_dpy {
20
uint32_t pos_y;
21
} egl_dpy;
22
23
+static GPtrArray *egl_dpys;
24
+
25
/* ------------------------------------------------------------------ */
26
27
static void egl_refresh(DisplayChangeListener *dcl)
@@ -220,6 +223,8 @@ static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
223
egl_dpy *edpy;
224
int idx;
225
226
+ egl_dpys = g_ptr_array_new();
227
+
228
for (idx = 0;; idx++) {
229
DisplayGLCtx *ctx;
230
@@ -232,15 +237,41 @@ static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
237
edpy->gls = qemu_gl_init_shader();
238
ctx = g_new0(DisplayGLCtx, 1);
239
ctx->ops = &eglctx_ops;
240
+ edpy->ctx = ctx;
241
qemu_console_set_display_gl_ctx(con, ctx);
242
qemu_console_register_listener(con, &edpy->dcl, &egl_ops);
243
+ g_ptr_array_add(egl_dpys, edpy);
244
+ }
245
+}
246
+
247
+static void egl_headless_cleanup(void)
248
+{
249
+ if (!egl_dpys) {
250
+ return;
251
}
252
+
253
+ for (guint i = 0; i < egl_dpys->len; i++) {
254
+ egl_dpy *edpy = g_ptr_array_index(egl_dpys, i);
255
+
256
+ qemu_console_unregister_listener(&edpy->dcl);
257
+ qemu_console_set_display_gl_ctx(edpy->dcl.con, NULL);
258
+ egl_fb_destroy(&edpy->guest_fb);
259
+ egl_fb_destroy(&edpy->cursor_fb);
260
+ egl_fb_destroy(&edpy->blit_fb);
261
+ qemu_gl_fini_shader(edpy->gls);
262
+ g_free(edpy->ctx);
263
+ g_free(edpy);
264
+ }
265
+ g_clear_pointer(&egl_dpys, g_ptr_array_unref);
266
+
267
+ egl_cleanup();
268
}
269
270
static QemuDisplay qemu_display_egl = {
271
.type = DISPLAY_TYPE_EGL_HEADLESS,
272
.early_init = early_egl_headless_init,
273
.init = egl_headless_init,
274
+ .cleanup = egl_headless_cleanup,
275
};
276
277
static void register_egl(void)
ui/egl-helpers.c
+19
@@ -733,3 +733,22 @@ bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
733
display_opengl = 1;
734
return true;
735
}
736
+
737
+void egl_cleanup(void)
738
+{
739
+ if (qemu_egl_rn_ctx) {
740
+ eglDestroyContext(qemu_egl_display, qemu_egl_rn_ctx);
741
+ qemu_egl_rn_ctx = NULL;
742
+ }
743
+
744
+#ifdef CONFIG_GBM
745
+ g_clear_pointer(&qemu_egl_rn_gbm_dev, gbm_device_destroy);
746
+ g_clear_fd(&qemu_egl_rn_fd, NULL);
747
+#endif
748
+
749
+ if (qemu_egl_display) {
750
+ eglReleaseThread();
751
+ eglTerminate(qemu_egl_display);
752
+ qemu_egl_display = NULL;
753
+ }
754
+}