diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2022-03-15 16:28:50 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2022-03-15 16:28:50 +0000 |
commit | e2fb7d8aa218256793df99571d16f92074258447 (patch) | |
tree | 013210834bdf41528641e21443bce32980981aa5 | |
parent | dee3a86d54f7d200e715843ee92aba2aaeb8382f (diff) | |
parent | e1c676a254b012779db87166a1f26db6886a8bce (diff) |
Merge tag 'dbus-pull-request' of gitlab.com:marcandre.lureau/qemu into staging
GL & D-Bus display related fixes
Hi,
Here are pending fixes related to D-Bus and GL, most of them reported thanks to
Akihiko Odaki.
# gpg: Signature made Tue 15 Mar 2022 09:36:45 GMT
# gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg: issuer "marcandre.lureau@redhat.com"
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5
* tag 'dbus-pull-request' of gitlab.com:marcandre.lureau/qemu:
ui/console: call gfx_switch() even if the current scanout is GL
ui/dbus: do not send 2d scanout until gfx_update
ui/dbus: fix texture sharing
ui/console: optionally update after gfx switch
ui/console: add a dpy_gfx_switch callback helper
ui/shader: free associated programs
ui/shader: fix potential leak of shader on error
ui/console: move console compatibility check to dcl_display_console()
ui/dbus: associate the DBusDisplayConsole listener with the given console
ui/console: egl-headless is compatible with non-gl listeners
ui/console: move dcl compatiblity check to a callback
ui/console: move check for compatible GL context
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | include/ui/console.h | 19 | ||||
-rw-r--r-- | ui/console.c | 104 | ||||
-rw-r--r-- | ui/dbus-console.c | 27 | ||||
-rw-r--r-- | ui/dbus-listener.c | 48 | ||||
-rw-r--r-- | ui/dbus.c | 35 | ||||
-rw-r--r-- | ui/dbus.h | 3 | ||||
-rw-r--r-- | ui/egl-headless.c | 17 | ||||
-rw-r--r-- | ui/gtk.c | 18 | ||||
-rw-r--r-- | ui/sdl2.c | 9 | ||||
-rw-r--r-- | ui/shader.c | 9 | ||||
-rw-r--r-- | ui/spice-display.c | 9 |
11 files changed, 202 insertions, 96 deletions
diff --git a/include/ui/console.h b/include/ui/console.h index f590819880..0f84861933 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -282,23 +282,28 @@ struct DisplayChangeListener { }; typedef struct DisplayGLCtxOps { - /* - * We only check if the GLCtx is compatible with a DCL via ops. A natural - * evolution of this would be a callback to check some runtime requirements - * and allow various DCL kinds. - */ - const DisplayChangeListenerOps *compatible_dcl; - + bool (*dpy_gl_ctx_is_compatible_dcl)(DisplayGLCtx *dgc, + DisplayChangeListener *dcl); QEMUGLContext (*dpy_gl_ctx_create)(DisplayGLCtx *dgc, QEMUGLParams *params); void (*dpy_gl_ctx_destroy)(DisplayGLCtx *dgc, QEMUGLContext ctx); int (*dpy_gl_ctx_make_current)(DisplayGLCtx *dgc, QEMUGLContext ctx); + void (*dpy_gl_ctx_create_texture)(DisplayGLCtx *dgc, + DisplaySurface *surface); + void (*dpy_gl_ctx_destroy_texture)(DisplayGLCtx *dgc, + DisplaySurface *surface); + void (*dpy_gl_ctx_update_texture)(DisplayGLCtx *dgc, + DisplaySurface *surface, + int x, int y, int w, int h); } DisplayGLCtxOps; struct DisplayGLCtx { const DisplayGLCtxOps *ops; +#ifdef CONFIG_OPENGL + QemuGLShader *gls; /* optional shared shader */ +#endif }; DisplayState *init_displaystate(void); diff --git a/ui/console.c b/ui/console.c index 365a2c14b8..da434ce1b2 100644 --- a/ui/console.c +++ b/ui/console.c @@ -148,6 +148,8 @@ static DisplayState *get_alloc_displaystate(void); static void text_console_update_cursor_timer(void); static void text_console_update_cursor(void *opaque); static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl); +static bool console_compatible_with(QemuConsole *con, + DisplayChangeListener *dcl, Error **errp); static void gui_update(void *opaque) { @@ -1056,24 +1058,66 @@ static void console_putchar(QemuConsole *s, int ch) } } +static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl, + struct DisplaySurface *new_surface, + bool update) +{ + if (dcl->ops->dpy_gfx_switch) { + dcl->ops->dpy_gfx_switch(dcl, new_surface); + } + + if (update && dcl->ops->dpy_gfx_update) { + dcl->ops->dpy_gfx_update(dcl, 0, 0, + surface_width(new_surface), + surface_height(new_surface)); + } +} + +static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface) +{ + if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) { + con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface); + } +} + +static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface) +{ + if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) { + con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface); + } +} + +static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface, + int x, int y, int w, int h) +{ + if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) { + con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h); + } +} + static void displaychangelistener_display_console(DisplayChangeListener *dcl, - QemuConsole *con) + QemuConsole *con, + Error **errp) { static const char nodev[] = "This VM has no graphic display device."; static DisplaySurface *dummy; - if (!con) { - if (!dcl->ops->dpy_gfx_switch) { - return; - } + if (!con || !console_compatible_with(con, dcl, errp)) { if (!dummy) { dummy = qemu_create_placeholder_surface(640, 480, nodev); } - dcl->ops->dpy_gfx_switch(dcl, dummy); + if (con) { + dpy_gfx_create_texture(con, dummy); + } + displaychangelistener_gfx_switch(dcl, dummy, TRUE); return; } + dpy_gfx_create_texture(con, con->surface); + displaychangelistener_gfx_switch(dcl, con->surface, + con->scanout.kind == SCANOUT_SURFACE); + if (con->scanout.kind == SCANOUT_DMABUF && displaychangelistener_has_dmabuf(dcl)) { dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf); @@ -1088,14 +1132,7 @@ static void displaychangelistener_display_console(DisplayChangeListener *dcl, con->scanout.texture.y, con->scanout.texture.width, con->scanout.texture.height); - } else if (con->scanout.kind == SCANOUT_SURFACE && - dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, con->surface); } - - dcl->ops->dpy_gfx_update(dcl, 0, 0, - qemu_console_get_width(con, 0), - qemu_console_get_height(con, 0)); } void console_select(unsigned int index) @@ -1114,7 +1151,7 @@ void console_select(unsigned int index) if (dcl->con != NULL) { continue; } - displaychangelistener_display_console(dcl, s); + displaychangelistener_display_console(dcl, s, NULL); } } if (ds->have_text) { @@ -1475,13 +1512,20 @@ static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl) return false; } -static bool dpy_compatible_with(QemuConsole *con, - DisplayChangeListener *dcl, Error **errp) +static bool console_compatible_with(QemuConsole *con, + DisplayChangeListener *dcl, Error **errp) { int flags; flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0; + if (console_has_gl(con) && + !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) { + error_setg(errp, "Display %s is incompatible with the GL context", + dcl->ops->dpy_name); + return false; + } + if (flags & GRAPHIC_FLAGS_GL && !console_has_gl(con)) { error_setg(errp, "The console requires a GL context."); @@ -1509,31 +1553,12 @@ void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl) con->gl = gl; } -static bool dpy_gl_compatible_with(QemuConsole *con, DisplayChangeListener *dcl) -{ - if (!con->gl) { - return true; - } - - return con->gl->ops->compatible_dcl == dcl->ops; -} - void register_displaychangelistener(DisplayChangeListener *dcl) { QemuConsole *con; assert(!dcl->ds); - if (dcl->con && !dpy_gl_compatible_with(dcl->con, dcl)) { - error_report("Display %s is incompatible with the GL context", - dcl->ops->dpy_name); - exit(1); - } - - if (dcl->con) { - dpy_compatible_with(dcl->con, dcl, &error_fatal); - } - trace_displaychangelistener_register(dcl, dcl->ops->dpy_name); dcl->ds = get_alloc_displaystate(); QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next); @@ -1544,7 +1569,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl) } else { con = active_console; } - displaychangelistener_display_console(dcl, con); + displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL); text_console_update_cursor(NULL); } @@ -1638,6 +1663,7 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) if (!qemu_console_is_visible(con)) { return; } + dpy_gfx_update_texture(con, con->surface, x, y, w, h); QLIST_FOREACH(dcl, &s->listeners, next) { if (con != (dcl->con ? dcl->con : active_console)) { continue; @@ -1682,14 +1708,14 @@ void dpy_gfx_replace_surface(QemuConsole *con, con->scanout.kind = SCANOUT_SURFACE; con->surface = surface; + dpy_gfx_create_texture(con, surface); QLIST_FOREACH(dcl, &s->listeners, next) { if (con != (dcl->con ? dcl->con : active_console)) { continue; } - if (dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, surface); - } + displaychangelistener_gfx_switch(dcl, surface, FALSE); } + dpy_gfx_destroy_texture(con, old_surface); qemu_free_displaysurface(old_surface); } diff --git a/ui/dbus-console.c b/ui/dbus-console.c index e062f721d7..898a4ac8a5 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -36,7 +36,6 @@ struct _DBusDisplayConsole { DisplayChangeListener dcl; DBusDisplay *display; - QemuConsole *con; GHashTable *listeners; QemuDBusDisplay1Console *iface; @@ -118,7 +117,7 @@ dbus_gl_scanout_update(DisplayChangeListener *dcl, { } -static const DisplayChangeListenerOps dbus_console_dcl_ops = { +const DisplayChangeListenerOps dbus_console_dcl_ops = { .dpy_name = "dbus-console", .dpy_gfx_switch = dbus_gfx_switch, .dpy_gfx_update = dbus_gfx_update, @@ -191,7 +190,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc, .height = arg_height, }; - if (!dpy_ui_info_supported(ddc->con)) { + if (!dpy_ui_info_supported(ddc->dcl.con)) { g_dbus_method_invocation_return_error(invocation, DBUS_DISPLAY_ERROR, DBUS_DISPLAY_ERROR_UNSUPPORTED, @@ -199,7 +198,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - dpy_set_ui_info(ddc->con, &info, false); + dpy_set_ui_info(ddc->dcl.con, &info, false); qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation); return DBUS_METHOD_INVOCATION_HANDLED; } @@ -335,8 +334,8 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - qemu_input_queue_rel(ddc->con, INPUT_AXIS_X, dx); - qemu_input_queue_rel(ddc->con, INPUT_AXIS_Y, dy); + qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx); + qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse, @@ -362,8 +361,8 @@ dbus_mouse_set_pos(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - width = qemu_console_get_width(ddc->con, 0); - height = qemu_console_get_height(ddc->con, 0); + width = qemu_console_get_width(ddc->dcl.con, 0); + height = qemu_console_get_height(ddc->dcl.con, 0); if (x >= width || y >= height) { g_dbus_method_invocation_return_error( invocation, DBUS_DISPLAY_ERROR, @@ -371,8 +370,8 @@ dbus_mouse_set_pos(DBusDisplayConsole *ddc, "Invalid mouse position"); return DBUS_METHOD_INVOCATION_HANDLED; } - qemu_input_queue_abs(ddc->con, INPUT_AXIS_X, x, 0, width); - qemu_input_queue_abs(ddc->con, INPUT_AXIS_Y, y, 0, height); + qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_X, x, 0, width); + qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_Y, y, 0, height); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse, @@ -388,7 +387,7 @@ dbus_mouse_press(DBusDisplayConsole *ddc, { trace_dbus_mouse_press(button); - qemu_input_queue_btn(ddc->con, button, true); + qemu_input_queue_btn(ddc->dcl.con, button, true); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation); @@ -403,7 +402,7 @@ dbus_mouse_release(DBusDisplayConsole *ddc, { trace_dbus_mouse_release(button); - qemu_input_queue_btn(ddc->con, button, false); + qemu_input_queue_btn(ddc->dcl.con, button, false); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation); @@ -424,7 +423,7 @@ dbus_mouse_mode_change(Notifier *notify, void *data) int dbus_display_console_get_index(DBusDisplayConsole *ddc) { - return qemu_console_get_index(ddc->con); + return qemu_console_get_index(ddc->dcl.con); } DBusDisplayConsole * @@ -446,7 +445,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con) "g-object-path", path, NULL); ddc->display = display; - ddc->con = con; + ddc->dcl.con = con; /* handle errors, and skip non graphics? */ qemu_console_fill_device_address( con, device_addr, sizeof(device_addr), NULL); diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 81c119b13a..f9fc8eda51 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -42,7 +42,6 @@ struct _DBusDisplayListener { DisplayChangeListener dcl; DisplaySurface *ds; - QemuGLShader *gls; int gl_updates; }; @@ -240,10 +239,6 @@ static void dbus_gl_gfx_update(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - if (ddl->ds) { - surface_gl_update_texture(ddl->gls, ddl->ds, x, y, w, h); - } - ddl->gl_updates++; } @@ -260,6 +255,26 @@ static void dbus_gfx_update(DisplayChangeListener *dcl, trace_dbus_update(x, y, w, h); + if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) { + v_data = g_variant_new_from_data( + G_VARIANT_TYPE("ay"), + surface_data(ddl->ds), + surface_stride(ddl->ds) * surface_height(ddl->ds), + TRUE, + (GDestroyNotify)pixman_image_unref, + pixman_image_ref(ddl->ds->image)); + qemu_dbus_display1_listener_call_scanout( + ddl->proxy, + surface_width(ddl->ds), + surface_height(ddl->ds), + surface_stride(ddl->ds), + surface_format(ddl->ds), + v_data, + G_DBUS_CALL_FLAGS_NONE, + DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + return; + } + /* make a copy, since gvariant only handles linear data */ img = pixman_image_create_bits(surface_format(ddl->ds), w, h, NULL, stride); @@ -285,15 +300,11 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - if (ddl->ds) { - surface_gl_destroy_texture(ddl->gls, ddl->ds); - } ddl->ds = new_surface; if (ddl->ds) { int width = surface_width(ddl->ds); int height = surface_height(ddl->ds); - surface_gl_create_texture(ddl->gls, ddl->ds); /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */ dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false, width, height, 0, 0, width, height); @@ -304,29 +315,12 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, struct DisplaySurface *new_surface) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - GVariant *v_data = NULL; ddl->ds = new_surface; if (!ddl->ds) { /* why not call disable instead? */ return; } - - v_data = g_variant_new_from_data( - G_VARIANT_TYPE("ay"), - surface_data(ddl->ds), - surface_stride(ddl->ds) * surface_height(ddl->ds), - TRUE, - (GDestroyNotify)pixman_image_unref, - pixman_image_ref(ddl->ds->image)); - qemu_dbus_display1_listener_call_scanout(ddl->proxy, - surface_width(ddl->ds), - surface_height(ddl->ds), - surface_stride(ddl->ds), - surface_format(ddl->ds), - v_data, - G_DBUS_CALL_FLAGS_NONE, - DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); } static void dbus_mouse_set(DisplayChangeListener *dcl, @@ -403,7 +397,6 @@ dbus_display_listener_dispose(GObject *object) g_clear_object(&ddl->conn); g_clear_pointer(&ddl->bus_name, g_free); g_clear_object(&ddl->proxy); - g_clear_pointer(&ddl->gls, qemu_gl_fini_shader); G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object); } @@ -414,7 +407,6 @@ dbus_display_listener_constructed(GObject *object) DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object); if (display_opengl) { - ddl->gls = qemu_gl_init_shader(); ddl->dcl.ops = &dbus_gl_dcl_ops; } else { ddl->dcl.ops = &dbus_dcl_ops; @@ -48,11 +48,40 @@ static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc, return qemu_egl_create_context(dgc, params); } +static bool +dbus_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dbus_gl_dcl_ops || dcl->ops == &dbus_console_dcl_ops; +} + +static void +dbus_create_texture(DisplayGLCtx *ctx, DisplaySurface *surface) +{ + surface_gl_create_texture(ctx->gls, surface); +} + +static void +dbus_destroy_texture(DisplayGLCtx *ctx, DisplaySurface *surface) +{ + surface_gl_destroy_texture(ctx->gls, surface); +} + +static void +dbus_update_texture(DisplayGLCtx *ctx, DisplaySurface *surface, + int x, int y, int w, int h) +{ + surface_gl_update_texture(ctx->gls, surface, x, y, w, h); +} + static const DisplayGLCtxOps dbus_gl_ops = { - .compatible_dcl = &dbus_gl_dcl_ops, + .dpy_gl_ctx_is_compatible_dcl = dbus_is_compatible_dcl, .dpy_gl_ctx_create = dbus_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = qemu_egl_make_context_current, + .dpy_gl_ctx_create_texture = dbus_create_texture, + .dpy_gl_ctx_destroy_texture = dbus_destroy_texture, + .dpy_gl_ctx_update_texture = dbus_update_texture, }; static NotifierList dbus_display_notifiers = @@ -83,6 +112,9 @@ dbus_display_init(Object *o) g_autoptr(GDBusObjectSkeleton) vm = NULL; dd->glctx.ops = &dbus_gl_ops; + if (display_opengl) { + dd->glctx.gls = qemu_gl_init_shader(); + } dd->iface = qemu_dbus_display1_vm_skeleton_new(); dd->consoles = g_ptr_array_new_with_free_func(g_object_unref); @@ -119,6 +151,7 @@ dbus_display_finalize(Object *o) g_clear_object(&dd->iface); g_free(dd->dbus_addr); g_free(dd->audiodev); + g_clear_pointer(&dd->glctx.gls, qemu_gl_fini_shader); dbus_display = NULL; } @@ -79,6 +79,9 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con); int dbus_display_console_get_index(DBusDisplayConsole *ddc); + +extern const DisplayChangeListenerOps dbus_console_dcl_ops; + #define DBUS_DISPLAY_TYPE_LISTENER dbus_display_listener_get_type() G_DECLARE_FINAL_TYPE(DBusDisplayListener, dbus_display_listener, diff --git a/ui/egl-headless.c b/ui/egl-headless.c index 94082a9da9..7a30fd9777 100644 --- a/ui/egl-headless.c +++ b/ui/egl-headless.c @@ -166,8 +166,23 @@ static const DisplayChangeListenerOps egl_ops = { .dpy_gl_update = egl_scanout_flush, }; +static bool +egl_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + if (!dcl->ops->dpy_gl_update) { + /* + * egl-headless is compatible with all 2d listeners, as it blits the GL + * updates on the 2d console surface. + */ + return true; + } + + return dcl->ops == &egl_ops; +} + static const DisplayGLCtxOps eglctx_ops = { - .compatible_dcl = &egl_ops, + .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl, .dpy_gl_ctx_create = egl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = qemu_egl_make_context_current, @@ -614,8 +614,15 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = { .dpy_has_dmabuf = gd_has_dmabuf, }; +static bool +gd_gl_area_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dcl_gl_area_ops; +} + static const DisplayGLCtxOps gl_area_ctx_ops = { - .compatible_dcl = &dcl_gl_area_ops, + .dpy_gl_ctx_is_compatible_dcl = gd_gl_area_is_compatible_dcl, .dpy_gl_ctx_create = gd_gl_area_create_context, .dpy_gl_ctx_destroy = gd_gl_area_destroy_context, .dpy_gl_ctx_make_current = gd_gl_area_make_current, @@ -641,8 +648,15 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_has_dmabuf = gd_has_dmabuf, }; +static bool +gd_egl_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dcl_egl_ops; +} + static const DisplayGLCtxOps egl_ctx_ops = { - .compatible_dcl = &dcl_egl_ops, + .dpy_gl_ctx_is_compatible_dcl = gd_egl_is_compatible_dcl, .dpy_gl_ctx_create = gd_egl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = gd_egl_make_current, @@ -788,8 +788,15 @@ static const DisplayChangeListenerOps dcl_gl_ops = { .dpy_gl_update = sdl2_gl_scanout_flush, }; +static bool +sdl2_gl_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dcl_gl_ops; +} + static const DisplayGLCtxOps gl_ctx_ops = { - .compatible_dcl = &dcl_gl_ops, + .dpy_gl_ctx_is_compatible_dcl = sdl2_gl_is_compatible_dcl, .dpy_gl_ctx_create = sdl2_gl_create_context, .dpy_gl_ctx_destroy = sdl2_gl_destroy_context, .dpy_gl_ctx_make_current = sdl2_gl_make_context_current, diff --git a/ui/shader.c b/ui/shader.c index e8b8d321b7..ab448c41d4 100644 --- a/ui/shader.c +++ b/ui/shader.c @@ -130,15 +130,17 @@ static GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag) static GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src, const GLchar *frag_src) { - GLuint vert_shader, frag_shader, program; + GLuint vert_shader, frag_shader, program = 0; vert_shader = qemu_gl_create_compile_shader(GL_VERTEX_SHADER, vert_src); frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src); if (!vert_shader || !frag_shader) { - return 0; + goto end; } program = qemu_gl_create_link_program(vert_shader, frag_shader); + +end: glDeleteShader(vert_shader); glDeleteShader(frag_shader); @@ -170,5 +172,8 @@ void qemu_gl_fini_shader(QemuGLShader *gls) if (!gls) { return; } + glDeleteProgram(gls->texture_blit_prog); + glDeleteProgram(gls->texture_blit_flip_prog); + glDeleteProgram(gls->texture_blit_vao); g_free(gls); } diff --git a/ui/spice-display.c b/ui/spice-display.c index a3078adf91..494168e7fe 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -1125,8 +1125,15 @@ static const DisplayChangeListenerOps display_listener_gl_ops = { .dpy_gl_update = qemu_spice_gl_update, }; +static bool +qemu_spice_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &display_listener_gl_ops; +} + static const DisplayGLCtxOps gl_ctx_ops = { - .compatible_dcl = &display_listener_gl_ops, + .dpy_gl_ctx_is_compatible_dcl = qemu_spice_is_compatible_dcl, .dpy_gl_ctx_create = qemu_spice_gl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = qemu_egl_make_context_current, |