@samitouri / QOSamiQemu / commits / a3cf9b55bb

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 +}