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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmIwXi0cHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5UkCD/9QzaSguM3OWRlZP6Xu
 QJ/T8yJSozzf/J7Q5cBr3VfGqgus79+mMqclIMotVLacwmMSPw+nVlNy9lpikK4J
 JPEcLxIfZfcRkG/FWaH289PAekTggE574RvFUBTz3N47G35M2V+SaLxdHYsh/mPT
 xXJ6UYtF9IvR9T9DQwN1KIwmsuckEDasSsY5YS1dkorpO6+hmKvfGhUhG9ehoqOE
 e87IZDIUeVR64ggoXAcC+ozqTWaf5eBBNVnQbc3kRaMVmbEE3JcK2Dspy/DNCHby
 0SJEyPlQI59gw/oI0ztJtHQ4j2EMGZGifqniZRAV/wJmxr2L1hIBU19L8Lb2/ka5
 Bz3JBh2rr2E1lyyNwlVlbjJCSJwDmz1Bx1JiX8l95FXwj/eblpChpH6cMmZ8Eyb+
 crRCEX8y+cZWqiBhuWnzE5JpupTVIVntxKjhtQwAcGD0/T5zSTKokRUZwNX2+FqU
 UcrkZQlhpWMQWfPvtMrj+JB4x+3SAZ5D0elL2uuO2ICFKVMN/95OWSRZP7MS7oVU
 21W2vuC+VagUzfasccGKc2G57HI2wriq4R7nfAEn5Semq4Eag1zrFhxGo9gI2w0k
 VuYV1PXGjBrq+SLYvNm+mTF/yjiVBwg+lBeJ5thk58j/ZTAItIpAISdArnmgw7Bt
 dwT4ER90Md1aAhALHFlfAuQjWA==
 =itk/
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2022-03-15 16:28:50 +00:00
commit e2fb7d8aa2
11 changed files with 202 additions and 96 deletions

View File

@ -282,23 +282,28 @@ struct DisplayChangeListener {
}; };
typedef struct DisplayGLCtxOps { typedef struct DisplayGLCtxOps {
/* bool (*dpy_gl_ctx_is_compatible_dcl)(DisplayGLCtx *dgc,
* We only check if the GLCtx is compatible with a DCL via ops. A natural DisplayChangeListener *dcl);
* evolution of this would be a callback to check some runtime requirements
* and allow various DCL kinds.
*/
const DisplayChangeListenerOps *compatible_dcl;
QEMUGLContext (*dpy_gl_ctx_create)(DisplayGLCtx *dgc, QEMUGLContext (*dpy_gl_ctx_create)(DisplayGLCtx *dgc,
QEMUGLParams *params); QEMUGLParams *params);
void (*dpy_gl_ctx_destroy)(DisplayGLCtx *dgc, void (*dpy_gl_ctx_destroy)(DisplayGLCtx *dgc,
QEMUGLContext ctx); QEMUGLContext ctx);
int (*dpy_gl_ctx_make_current)(DisplayGLCtx *dgc, int (*dpy_gl_ctx_make_current)(DisplayGLCtx *dgc,
QEMUGLContext ctx); 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; } DisplayGLCtxOps;
struct DisplayGLCtx { struct DisplayGLCtx {
const DisplayGLCtxOps *ops; const DisplayGLCtxOps *ops;
#ifdef CONFIG_OPENGL
QemuGLShader *gls; /* optional shared shader */
#endif
}; };
DisplayState *init_displaystate(void); DisplayState *init_displaystate(void);

View File

@ -148,6 +148,8 @@ static DisplayState *get_alloc_displaystate(void);
static void text_console_update_cursor_timer(void); static void text_console_update_cursor_timer(void);
static void text_console_update_cursor(void *opaque); static void text_console_update_cursor(void *opaque);
static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl); static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
static bool console_compatible_with(QemuConsole *con,
DisplayChangeListener *dcl, Error **errp);
static void gui_update(void *opaque) 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, static void displaychangelistener_display_console(DisplayChangeListener *dcl,
QemuConsole *con) QemuConsole *con,
Error **errp)
{ {
static const char nodev[] = static const char nodev[] =
"This VM has no graphic display device."; "This VM has no graphic display device.";
static DisplaySurface *dummy; static DisplaySurface *dummy;
if (!con) { if (!con || !console_compatible_with(con, dcl, errp)) {
if (!dcl->ops->dpy_gfx_switch) {
return;
}
if (!dummy) { if (!dummy) {
dummy = qemu_create_placeholder_surface(640, 480, nodev); 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; 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 && if (con->scanout.kind == SCANOUT_DMABUF &&
displaychangelistener_has_dmabuf(dcl)) { displaychangelistener_has_dmabuf(dcl)) {
dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf); 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.y,
con->scanout.texture.width, con->scanout.texture.width,
con->scanout.texture.height); 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) void console_select(unsigned int index)
@ -1114,7 +1151,7 @@ void console_select(unsigned int index)
if (dcl->con != NULL) { if (dcl->con != NULL) {
continue; continue;
} }
displaychangelistener_display_console(dcl, s); displaychangelistener_display_console(dcl, s, NULL);
} }
} }
if (ds->have_text) { if (ds->have_text) {
@ -1475,13 +1512,20 @@ static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
return false; return false;
} }
static bool dpy_compatible_with(QemuConsole *con, static bool console_compatible_with(QemuConsole *con,
DisplayChangeListener *dcl, Error **errp) DisplayChangeListener *dcl, Error **errp)
{ {
int flags; int flags;
flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0; 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 && if (flags & GRAPHIC_FLAGS_GL &&
!console_has_gl(con)) { !console_has_gl(con)) {
error_setg(errp, "The console requires a GL context."); 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; 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) void register_displaychangelistener(DisplayChangeListener *dcl)
{ {
QemuConsole *con; QemuConsole *con;
assert(!dcl->ds); 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); trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
dcl->ds = get_alloc_displaystate(); dcl->ds = get_alloc_displaystate();
QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next); QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
@ -1544,7 +1569,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
} else { } else {
con = active_console; con = active_console;
} }
displaychangelistener_display_console(dcl, con); displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL);
text_console_update_cursor(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)) { if (!qemu_console_is_visible(con)) {
return; return;
} }
dpy_gfx_update_texture(con, con->surface, x, y, w, h);
QLIST_FOREACH(dcl, &s->listeners, next) { QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != (dcl->con ? dcl->con : active_console)) { if (con != (dcl->con ? dcl->con : active_console)) {
continue; continue;
@ -1682,14 +1708,14 @@ void dpy_gfx_replace_surface(QemuConsole *con,
con->scanout.kind = SCANOUT_SURFACE; con->scanout.kind = SCANOUT_SURFACE;
con->surface = surface; con->surface = surface;
dpy_gfx_create_texture(con, surface);
QLIST_FOREACH(dcl, &s->listeners, next) { QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != (dcl->con ? dcl->con : active_console)) { if (con != (dcl->con ? dcl->con : active_console)) {
continue; continue;
} }
if (dcl->ops->dpy_gfx_switch) { displaychangelistener_gfx_switch(dcl, surface, FALSE);
dcl->ops->dpy_gfx_switch(dcl, surface);
}
} }
dpy_gfx_destroy_texture(con, old_surface);
qemu_free_displaysurface(old_surface); qemu_free_displaysurface(old_surface);
} }

View File

@ -36,7 +36,6 @@ struct _DBusDisplayConsole {
DisplayChangeListener dcl; DisplayChangeListener dcl;
DBusDisplay *display; DBusDisplay *display;
QemuConsole *con;
GHashTable *listeners; GHashTable *listeners;
QemuDBusDisplay1Console *iface; 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_name = "dbus-console",
.dpy_gfx_switch = dbus_gfx_switch, .dpy_gfx_switch = dbus_gfx_switch,
.dpy_gfx_update = dbus_gfx_update, .dpy_gfx_update = dbus_gfx_update,
@ -191,7 +190,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
.height = arg_height, .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, g_dbus_method_invocation_return_error(invocation,
DBUS_DISPLAY_ERROR, DBUS_DISPLAY_ERROR,
DBUS_DISPLAY_ERROR_UNSUPPORTED, DBUS_DISPLAY_ERROR_UNSUPPORTED,
@ -199,7 +198,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED; 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); qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation);
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
@ -335,8 +334,8 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
qemu_input_queue_rel(ddc->con, INPUT_AXIS_X, dx); qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx);
qemu_input_queue_rel(ddc->con, INPUT_AXIS_Y, dy); qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy);
qemu_input_event_sync(); qemu_input_event_sync();
qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse, 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; return DBUS_METHOD_INVOCATION_HANDLED;
} }
width = qemu_console_get_width(ddc->con, 0); width = qemu_console_get_width(ddc->dcl.con, 0);
height = qemu_console_get_height(ddc->con, 0); height = qemu_console_get_height(ddc->dcl.con, 0);
if (x >= width || y >= height) { if (x >= width || y >= height) {
g_dbus_method_invocation_return_error( g_dbus_method_invocation_return_error(
invocation, DBUS_DISPLAY_ERROR, invocation, DBUS_DISPLAY_ERROR,
@ -371,8 +370,8 @@ dbus_mouse_set_pos(DBusDisplayConsole *ddc,
"Invalid mouse position"); "Invalid mouse position");
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
qemu_input_queue_abs(ddc->con, INPUT_AXIS_X, x, 0, width); qemu_input_queue_abs(ddc->dcl.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_Y, y, 0, height);
qemu_input_event_sync(); qemu_input_event_sync();
qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse, 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); 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_input_event_sync();
qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation); qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation);
@ -403,7 +402,7 @@ dbus_mouse_release(DBusDisplayConsole *ddc,
{ {
trace_dbus_mouse_release(button); 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_input_event_sync();
qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation); 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) int dbus_display_console_get_index(DBusDisplayConsole *ddc)
{ {
return qemu_console_get_index(ddc->con); return qemu_console_get_index(ddc->dcl.con);
} }
DBusDisplayConsole * DBusDisplayConsole *
@ -446,7 +445,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
"g-object-path", path, "g-object-path", path,
NULL); NULL);
ddc->display = display; ddc->display = display;
ddc->con = con; ddc->dcl.con = con;
/* handle errors, and skip non graphics? */ /* handle errors, and skip non graphics? */
qemu_console_fill_device_address( qemu_console_fill_device_address(
con, device_addr, sizeof(device_addr), NULL); con, device_addr, sizeof(device_addr), NULL);

View File

@ -42,7 +42,6 @@ struct _DBusDisplayListener {
DisplayChangeListener dcl; DisplayChangeListener dcl;
DisplaySurface *ds; DisplaySurface *ds;
QemuGLShader *gls;
int gl_updates; int gl_updates;
}; };
@ -240,10 +239,6 @@ static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
{ {
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, 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++; ddl->gl_updates++;
} }
@ -260,6 +255,26 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
trace_dbus_update(x, y, w, h); 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 */ /* make a copy, since gvariant only handles linear data */
img = pixman_image_create_bits(surface_format(ddl->ds), img = pixman_image_create_bits(surface_format(ddl->ds),
w, h, NULL, stride); w, h, NULL, stride);
@ -285,15 +300,11 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
{ {
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
if (ddl->ds) {
surface_gl_destroy_texture(ddl->gls, ddl->ds);
}
ddl->ds = new_surface; ddl->ds = new_surface;
if (ddl->ds) { if (ddl->ds) {
int width = surface_width(ddl->ds); int width = surface_width(ddl->ds);
int height = surface_height(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) */ /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false, dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false,
width, height, 0, 0, width, height); width, height, 0, 0, width, height);
@ -304,29 +315,12 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface) struct DisplaySurface *new_surface)
{ {
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
GVariant *v_data = NULL;
ddl->ds = new_surface; ddl->ds = new_surface;
if (!ddl->ds) { if (!ddl->ds) {
/* why not call disable instead? */ /* why not call disable instead? */
return; 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, static void dbus_mouse_set(DisplayChangeListener *dcl,
@ -403,7 +397,6 @@ dbus_display_listener_dispose(GObject *object)
g_clear_object(&ddl->conn); g_clear_object(&ddl->conn);
g_clear_pointer(&ddl->bus_name, g_free); g_clear_pointer(&ddl->bus_name, g_free);
g_clear_object(&ddl->proxy); g_clear_object(&ddl->proxy);
g_clear_pointer(&ddl->gls, qemu_gl_fini_shader);
G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object); 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); DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
if (display_opengl) { if (display_opengl) {
ddl->gls = qemu_gl_init_shader();
ddl->dcl.ops = &dbus_gl_dcl_ops; ddl->dcl.ops = &dbus_gl_dcl_ops;
} else { } else {
ddl->dcl.ops = &dbus_dcl_ops; ddl->dcl.ops = &dbus_dcl_ops;

View File

@ -48,11 +48,40 @@ static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
return qemu_egl_create_context(dgc, params); 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 = { 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_create = dbus_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
.dpy_gl_ctx_make_current = qemu_egl_make_context_current, .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 = static NotifierList dbus_display_notifiers =
@ -83,6 +112,9 @@ dbus_display_init(Object *o)
g_autoptr(GDBusObjectSkeleton) vm = NULL; g_autoptr(GDBusObjectSkeleton) vm = NULL;
dd->glctx.ops = &dbus_gl_ops; 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->iface = qemu_dbus_display1_vm_skeleton_new();
dd->consoles = g_ptr_array_new_with_free_func(g_object_unref); 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_clear_object(&dd->iface);
g_free(dd->dbus_addr); g_free(dd->dbus_addr);
g_free(dd->audiodev); g_free(dd->audiodev);
g_clear_pointer(&dd->glctx.gls, qemu_gl_fini_shader);
dbus_display = NULL; dbus_display = NULL;
} }

View File

@ -79,6 +79,9 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con);
int int
dbus_display_console_get_index(DBusDisplayConsole *ddc); dbus_display_console_get_index(DBusDisplayConsole *ddc);
extern const DisplayChangeListenerOps dbus_console_dcl_ops;
#define DBUS_DISPLAY_TYPE_LISTENER dbus_display_listener_get_type() #define DBUS_DISPLAY_TYPE_LISTENER dbus_display_listener_get_type()
G_DECLARE_FINAL_TYPE(DBusDisplayListener, G_DECLARE_FINAL_TYPE(DBusDisplayListener,
dbus_display_listener, dbus_display_listener,

View File

@ -166,8 +166,23 @@ static const DisplayChangeListenerOps egl_ops = {
.dpy_gl_update = egl_scanout_flush, .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 = { 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_create = egl_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
.dpy_gl_ctx_make_current = qemu_egl_make_context_current, .dpy_gl_ctx_make_current = qemu_egl_make_context_current,

View File

@ -614,8 +614,15 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {
.dpy_has_dmabuf = gd_has_dmabuf, .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 = { 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_create = gd_gl_area_create_context,
.dpy_gl_ctx_destroy = gd_gl_area_destroy_context, .dpy_gl_ctx_destroy = gd_gl_area_destroy_context,
.dpy_gl_ctx_make_current = gd_gl_area_make_current, .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, .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 = { 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_create = gd_egl_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
.dpy_gl_ctx_make_current = gd_egl_make_current, .dpy_gl_ctx_make_current = gd_egl_make_current,

View File

@ -788,8 +788,15 @@ static const DisplayChangeListenerOps dcl_gl_ops = {
.dpy_gl_update = sdl2_gl_scanout_flush, .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 = { 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_create = sdl2_gl_create_context,
.dpy_gl_ctx_destroy = sdl2_gl_destroy_context, .dpy_gl_ctx_destroy = sdl2_gl_destroy_context,
.dpy_gl_ctx_make_current = sdl2_gl_make_context_current, .dpy_gl_ctx_make_current = sdl2_gl_make_context_current,

View File

@ -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, static GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
const GLchar *frag_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); vert_shader = qemu_gl_create_compile_shader(GL_VERTEX_SHADER, vert_src);
frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src); frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src);
if (!vert_shader || !frag_shader) { if (!vert_shader || !frag_shader) {
return 0; goto end;
} }
program = qemu_gl_create_link_program(vert_shader, frag_shader); program = qemu_gl_create_link_program(vert_shader, frag_shader);
end:
glDeleteShader(vert_shader); glDeleteShader(vert_shader);
glDeleteShader(frag_shader); glDeleteShader(frag_shader);
@ -170,5 +172,8 @@ void qemu_gl_fini_shader(QemuGLShader *gls)
if (!gls) { if (!gls) {
return; return;
} }
glDeleteProgram(gls->texture_blit_prog);
glDeleteProgram(gls->texture_blit_flip_prog);
glDeleteProgram(gls->texture_blit_vao);
g_free(gls); g_free(gls);
} }

View File

@ -1125,8 +1125,15 @@ static const DisplayChangeListenerOps display_listener_gl_ops = {
.dpy_gl_update = qemu_spice_gl_update, .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 = { 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_create = qemu_spice_gl_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
.dpy_gl_ctx_make_current = qemu_egl_make_context_current, .dpy_gl_ctx_make_current = qemu_egl_make_context_current,