ui: dbus & misc fixes

v2:
 - fix crash spotted by avocado VNC test
 -----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmQPgRIcHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5QDFEACef6cbSlTtQji1hV+x
 FM2ESPn0tgg9YVmtjsC1zqcdOEKsbs+2SQxBSs6tvQGwX5CgtnmyEsH5/Y4+TU64
 r6dvGAhokEkhiyHwnC+DFw0ajYAaDK96RfJ02tPQ58lrBTyioKZH9K/3mB6pMFEG
 aroE1Z3SQqqMnP+zsQ64nYuJrTXnv9iFejIxnuou+LyXdxmwLWAl5e47eZYaTmrh
 RrJYbCyHbiL5bx6mOmAL1XlO9jJD4o0FrqRWFn4zz1T+w4FvUC/uX52XwRn1G/Hk
 oHNnJBt95czCQ3S43xX0VTVrT9vLAptQzQc45KfegRL3XqPLgTgn4eocBQCYLmHZ
 jKnUsE9VjBNCbkIzgfN9RP/zEklD/3lAHzrW5US7q7oTTYksyxN+pmvfrYbUvKWP
 Oq/EQtpv66R06hjpxD76ime4+Y8WN7I3F/fJS8jl2QDy5I/2IzFSIOD9Rt5PGbky
 xsIdr7QPzlN4ZKpnsRCNeEPwcR/kiv4grIF7jBAxxz3k5UENtIVSJkHBEEQjMy8O
 +ZCvnHsbjPGxFtnlNTvtGsR2hiKYRCJSG/C4YQryTDWoScomlF6UWxzbapjs9CRW
 /GR+98Z2QfwOtRRRteRRt9UFdC/T0DquxnRyJxa5N4VxMiWzmhtCOzmn4oc1THbG
 5UqDhRNSWEJn9iIvKca5ahSWLw==
 =Rjcs
 -----END PGP SIGNATURE-----

Merge tag 'display-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging

ui: dbus & misc fixes

v2:
- fix crash spotted by avocado VNC test

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmQPgRIcHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5QDFEACef6cbSlTtQji1hV+x
# FM2ESPn0tgg9YVmtjsC1zqcdOEKsbs+2SQxBSs6tvQGwX5CgtnmyEsH5/Y4+TU64
# r6dvGAhokEkhiyHwnC+DFw0ajYAaDK96RfJ02tPQ58lrBTyioKZH9K/3mB6pMFEG
# aroE1Z3SQqqMnP+zsQ64nYuJrTXnv9iFejIxnuou+LyXdxmwLWAl5e47eZYaTmrh
# RrJYbCyHbiL5bx6mOmAL1XlO9jJD4o0FrqRWFn4zz1T+w4FvUC/uX52XwRn1G/Hk
# oHNnJBt95czCQ3S43xX0VTVrT9vLAptQzQc45KfegRL3XqPLgTgn4eocBQCYLmHZ
# jKnUsE9VjBNCbkIzgfN9RP/zEklD/3lAHzrW5US7q7oTTYksyxN+pmvfrYbUvKWP
# Oq/EQtpv66R06hjpxD76ime4+Y8WN7I3F/fJS8jl2QDy5I/2IzFSIOD9Rt5PGbky
# xsIdr7QPzlN4ZKpnsRCNeEPwcR/kiv4grIF7jBAxxz3k5UENtIVSJkHBEEQjMy8O
# +ZCvnHsbjPGxFtnlNTvtGsR2hiKYRCJSG/C4YQryTDWoScomlF6UWxzbapjs9CRW
# /GR+98Z2QfwOtRRRteRRt9UFdC/T0DquxnRyJxa5N4VxMiWzmhtCOzmn4oc1THbG
# 5UqDhRNSWEJn9iIvKca5ahSWLw==
# =Rjcs
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 13 Mar 2023 20:01:22 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 'display-pull-request' of https://gitlab.com/marcandre.lureau/qemu:
  ui/dbus: restrict opengl to gbm-enabled config
  ui/dbus: do not require opengl & gbm
  ui: introduce egl_init()
  ui/sdl: try to instantiate the matching opengl renderer
  ui/sdl: add QEMU_ENABLE_SDL_LOGGING setting/environment
  ui/egl: print EGL error, helping debugging
  ui/shader: fix #version directive must occur on first line
  ui/sdl: get the GL context from the window
  ui: set cursor position upon listener registration
  ui: set cursor upon listener registration
  ui: keep current cursor with QemuConsole
  ui: rename cursor_{get->ref}, return it
  ui: rename cursor_{put->unref}
  meson: ensure dbus-display generated code is built before other units
  ui/dbus: set mouse is-absolute during console creation
  audio/dbus: there are no sender for p2p mode
  ui/dbus: unregister clipboard on connection close
  ui/dbus: initialize cursor_fb

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-03-14 14:28:58 +00:00
commit 7c3cc428c7
26 changed files with 211 additions and 81 deletions

View file

@ -143,7 +143,7 @@ struct audio_driver {
void *(*init) (Audiodev *); void *(*init) (Audiodev *);
void (*fini) (void *); void (*fini) (void *);
#ifdef CONFIG_GIO #ifdef CONFIG_GIO
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager); void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p);
#endif #endif
struct audio_pcm_ops *pcm_ops; struct audio_pcm_ops *pcm_ops;
int can_be_default; int can_be_default;

View file

@ -43,6 +43,7 @@
typedef struct DBusAudio { typedef struct DBusAudio {
GDBusObjectManagerServer *server; GDBusObjectManagerServer *server;
bool p2p;
GDBusObjectSkeleton *audio; GDBusObjectSkeleton *audio;
QemuDBusDisplay1Audio *iface; QemuDBusDisplay1Audio *iface;
GHashTable *out_listeners; GHashTable *out_listeners;
@ -448,7 +449,8 @@ dbus_audio_register_listener(AudioState *s,
bool out) bool out)
{ {
DBusAudio *da = s->drv_opaque; DBusAudio *da = s->drv_opaque;
const char *sender = g_dbus_method_invocation_get_sender(invocation); const char *sender =
da->p2p ? "p2p" : g_dbus_method_invocation_get_sender(invocation);
g_autoptr(GDBusConnection) listener_conn = NULL; g_autoptr(GDBusConnection) listener_conn = NULL;
g_autoptr(GError) err = NULL; g_autoptr(GError) err = NULL;
g_autoptr(GSocket) socket = NULL; g_autoptr(GSocket) socket = NULL;
@ -591,7 +593,7 @@ dbus_audio_register_in_listener(AudioState *s,
} }
static void static void
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server) dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
{ {
DBusAudio *da = s->drv_opaque; DBusAudio *da = s->drv_opaque;
@ -599,6 +601,7 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server)
g_assert(!da->server); g_assert(!da->server);
da->server = g_object_ref(server); da->server = g_object_ref(server);
da->p2p = p2p;
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH); da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
da->iface = qemu_dbus_display1_audio_skeleton_new(); da->iface = qemu_dbus_display1_audio_skeleton_new();

View file

@ -290,7 +290,7 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor,
return c; return c;
fail: fail:
cursor_put(c); cursor_unref(c);
return NULL; return NULL;
} }
@ -336,7 +336,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
} }
qemu_mutex_lock(&qxl->ssd.lock); qemu_mutex_lock(&qxl->ssd.lock);
if (qxl->ssd.cursor) { if (qxl->ssd.cursor) {
cursor_put(qxl->ssd.cursor); cursor_unref(qxl->ssd.cursor);
} }
qxl->ssd.cursor = c; qxl->ssd.cursor = c;
qxl->ssd.mouse_x = cmd->u.set.position.x; qxl->ssd.mouse_x = cmd->u.set.position.x;

View file

@ -299,7 +299,7 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
qxl->guest_cursor = 0; qxl->guest_cursor = 0;
qemu_mutex_unlock(&qxl->track_lock); qemu_mutex_unlock(&qxl->track_lock);
if (qxl->ssd.cursor) { if (qxl->ssd.cursor) {
cursor_put(qxl->ssd.cursor); cursor_unref(qxl->ssd.cursor);
} }
qxl->ssd.cursor = cursor_builtin_hidden(); qxl->ssd.cursor = cursor_builtin_hidden();
} }

View file

@ -550,12 +550,12 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
default: default:
fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n", fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n",
__func__, c->bpp); __func__, c->bpp);
cursor_put(qc); cursor_unref(qc);
qc = cursor_builtin_left_ptr(); qc = cursor_builtin_left_ptr();
} }
dpy_cursor_define(s->vga.con, qc); dpy_cursor_define(s->vga.con, qc);
cursor_put(qc); cursor_unref(qc);
} }
#endif #endif

View file

@ -151,8 +151,8 @@ typedef struct QEMUCursor {
} QEMUCursor; } QEMUCursor;
QEMUCursor *cursor_alloc(int width, int height); QEMUCursor *cursor_alloc(int width, int height);
void cursor_get(QEMUCursor *c); QEMUCursor *cursor_ref(QEMUCursor *c);
void cursor_put(QEMUCursor *c); void cursor_unref(QEMUCursor *c);
QEMUCursor *cursor_builtin_hidden(void); QEMUCursor *cursor_builtin_hidden(void);
QEMUCursor *cursor_builtin_left_ptr(void); QEMUCursor *cursor_builtin_left_ptr(void);
void cursor_print_ascii_art(QEMUCursor *c, const char *prefix); void cursor_print_ascii_art(QEMUCursor *c, const char *prefix);
@ -459,6 +459,7 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
QemuConsole *qemu_console_lookup_by_device_name(const char *device_id, QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
uint32_t head, Error **errp); uint32_t head, Error **errp);
QemuConsole *qemu_console_lookup_unused(void); QemuConsole *qemu_console_lookup_unused(void);
QEMUCursor *qemu_console_get_cursor(QemuConsole *con);
bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con);
bool qemu_console_is_fixedsize(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con);

View file

@ -22,6 +22,8 @@ typedef struct egl_fb {
QemuDmaBuf *dmabuf; QemuDmaBuf *dmabuf;
} egl_fb; } egl_fb;
#define EGL_FB_INIT { 0, }
void egl_fb_destroy(egl_fb *fb); void egl_fb_destroy(egl_fb *fb);
void egl_fb_setup_default(egl_fb *fb, int width, int height); void egl_fb_setup_default(egl_fb *fb, int width, int height);
void egl_fb_setup_for_tex(egl_fb *fb, int width, int height, void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
@ -63,4 +65,6 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode);
EGLContext qemu_egl_init_ctx(void); EGLContext qemu_egl_init_ctx(void);
bool qemu_egl_has_dmabuf(void); bool qemu_egl_has_dmabuf(void);
bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp);
#endif /* EGL_HELPERS_H */ #endif /* EGL_HELPERS_H */

View file

@ -1746,8 +1746,8 @@ dbus_display = get_option('dbus_display') \
error_message: '-display dbus requires glib>=2.64') \ error_message: '-display dbus requires glib>=2.64') \
.require(gdbus_codegen.found(), .require(gdbus_codegen.found(),
error_message: gdbus_codegen_error.format('-display dbus')) \ error_message: gdbus_codegen_error.format('-display dbus')) \
.require(opengl.found() and gbm.found(), .require(targetos != 'windows',
error_message: '-display dbus requires epoxy/egl and gbm') \ error_message: '-display dbus is not available on Windows') \
.allowed() .allowed()
have_virtfs = get_option('virtfs') \ have_virtfs = get_option('virtfs') \

View file

@ -101,7 +101,7 @@ qtests_i386 = \
'numa-test' 'numa-test'
] ]
if dbus_display if dbus_display and targetos != 'windows'
qtests_i386 += ['dbus-display-test'] qtests_i386 += ['dbus-display-test']
endif endif

View file

@ -94,6 +94,8 @@ struct QemuConsole {
uint32_t head; uint32_t head;
QemuUIInfo ui_info; QemuUIInfo ui_info;
QEMUTimer *ui_timer; QEMUTimer *ui_timer;
QEMUCursor *cursor;
int cursor_x, cursor_y, cursor_on;
const GraphicHwOps *hw_ops; const GraphicHwOps *hw_ops;
void *hw; void *hw;
@ -1661,6 +1663,12 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
con = active_console; con = active_console;
} }
displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL); displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL);
if (con && con->cursor && dcl->ops->dpy_cursor_define) {
dcl->ops->dpy_cursor_define(dcl, con->cursor);
}
if (con && dcl->ops->dpy_mouse_set) {
dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
}
text_console_update_cursor(NULL); text_console_update_cursor(NULL);
} }
@ -1905,6 +1913,9 @@ void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
DisplayState *s = con->ds; DisplayState *s = con->ds;
DisplayChangeListener *dcl; DisplayChangeListener *dcl;
con->cursor_x = x;
con->cursor_y = y;
con->cursor_on = on;
if (!qemu_console_is_visible(con)) { if (!qemu_console_is_visible(con)) {
return; return;
} }
@ -1923,6 +1934,8 @@ void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
DisplayState *s = con->ds; DisplayState *s = con->ds;
DisplayChangeListener *dcl; DisplayChangeListener *dcl;
cursor_unref(con->cursor);
con->cursor = cursor_ref(cursor);
if (!qemu_console_is_visible(con)) { if (!qemu_console_is_visible(con)) {
return; return;
} }
@ -2288,6 +2301,11 @@ QemuConsole *qemu_console_lookup_unused(void)
return NULL; return NULL;
} }
QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
{
return con->cursor;
}
bool qemu_console_is_visible(QemuConsole *con) bool qemu_console_is_visible(QemuConsole *con)
{ {
return (con == active_console) || (con->dcls > 0); return (con == active_console) || (con->dcls > 0);

View file

@ -106,12 +106,13 @@ QEMUCursor *cursor_alloc(int width, int height)
return c; return c;
} }
void cursor_get(QEMUCursor *c) QEMUCursor *cursor_ref(QEMUCursor *c)
{ {
c->refcount++; c->refcount++;
return c;
} }
void cursor_put(QEMUCursor *c) void cursor_unref(QEMUCursor *c)
{ {
if (c == NULL) if (c == NULL)
return; return;

View file

@ -204,15 +204,6 @@ dbus_clipboard_unregister_proxy(DBusDisplay *dpy)
g_clear_object(&dpy->clipboard_proxy); g_clear_object(&dpy->clipboard_proxy);
} }
static void
dbus_on_clipboard_proxy_name_owner_changed(
DBusDisplay *dpy,
GObject *object,
GParamSpec *pspec)
{
dbus_clipboard_unregister_proxy(dpy);
}
static gboolean static gboolean
dbus_clipboard_register( dbus_clipboard_register(
DBusDisplay *dpy, DBusDisplay *dpy,
@ -220,6 +211,7 @@ dbus_clipboard_register(
{ {
g_autoptr(GError) err = NULL; g_autoptr(GError) err = NULL;
const char *name = NULL; const char *name = NULL;
GDBusConnection *connection = g_dbus_method_invocation_get_connection(invocation);
if (dpy->clipboard_proxy) { if (dpy->clipboard_proxy) {
g_dbus_method_invocation_return_error( g_dbus_method_invocation_return_error(
@ -232,7 +224,7 @@ dbus_clipboard_register(
dpy->clipboard_proxy = dpy->clipboard_proxy =
qemu_dbus_display1_clipboard_proxy_new_sync( qemu_dbus_display1_clipboard_proxy_new_sync(
g_dbus_method_invocation_get_connection(invocation), connection,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
g_dbus_method_invocation_get_sender(invocation), g_dbus_method_invocation_get_sender(invocation),
"/org/qemu/Display1/Clipboard", "/org/qemu/Display1/Clipboard",
@ -252,7 +244,11 @@ dbus_clipboard_register(
g_object_connect(dpy->clipboard_proxy, g_object_connect(dpy->clipboard_proxy,
"swapped-signal::notify::g-name-owner", "swapped-signal::notify::g-name-owner",
dbus_on_clipboard_proxy_name_owner_changed, dpy, dbus_clipboard_unregister_proxy, dpy,
NULL);
g_object_connect(connection,
"swapped-signal::closed",
dbus_clipboard_unregister_proxy, dpy,
NULL); NULL);
qemu_clipboard_reset_serial(); qemu_clipboard_reset_serial();

View file

@ -411,15 +411,21 @@ dbus_mouse_release(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
static void
dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc)
{
g_object_set(ddc->iface_mouse,
"is-absolute", qemu_input_is_absolute(),
NULL);
}
static void static void
dbus_mouse_mode_change(Notifier *notify, void *data) dbus_mouse_mode_change(Notifier *notify, void *data)
{ {
DBusDisplayConsole *ddc = DBusDisplayConsole *ddc =
container_of(notify, DBusDisplayConsole, mouse_mode_notifier); container_of(notify, DBusDisplayConsole, mouse_mode_notifier);
g_object_set(ddc->iface_mouse, dbus_mouse_update_is_absolute(ddc);
"is-absolute", qemu_input_is_absolute(),
NULL);
} }
int dbus_display_console_get_index(DBusDisplayConsole *ddc) int dbus_display_console_get_index(DBusDisplayConsole *ddc)
@ -492,6 +498,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
register_displaychangelistener(&ddc->dcl); register_displaychangelistener(&ddc->dcl);
ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change; ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier); qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
dbus_mouse_update_is_absolute(ddc);
return ddc; return ddc;
} }

View file

@ -27,9 +27,11 @@
#include "dbus.h" #include "dbus.h"
#include <gio/gunixfdlist.h> #include <gio/gunixfdlist.h>
#ifdef CONFIG_OPENGL
#include "ui/shader.h" #include "ui/shader.h"
#include "ui/egl-helpers.h" #include "ui/egl-helpers.h"
#include "ui/egl-context.h" #include "ui/egl-context.h"
#endif
#include "trace.h" #include "trace.h"
struct _DBusDisplayListener { struct _DBusDisplayListener {
@ -48,6 +50,7 @@ struct _DBusDisplayListener {
G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT) G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
#ifdef CONFIG_GBM
static void dbus_update_gl_cb(GObject *source_object, static void dbus_update_gl_cb(GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
gpointer user_data) gpointer user_data)
@ -149,7 +152,7 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
DisplaySurface *ds; DisplaySurface *ds;
GVariant *v_data = NULL; GVariant *v_data = NULL;
egl_fb cursor_fb; egl_fb cursor_fb = EGL_FB_INIT;
if (!dmabuf) { if (!dmabuf) {
qemu_dbus_display1_listener_call_mouse_set( qemu_dbus_display1_listener_call_mouse_set(
@ -229,12 +232,14 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
ddl->gl_updates = 0; ddl->gl_updates = 0;
} }
} }
#endif
static void dbus_refresh(DisplayChangeListener *dcl) static void dbus_refresh(DisplayChangeListener *dcl)
{ {
graphic_hw_update(dcl->con); graphic_hw_update(dcl->con);
} }
#ifdef CONFIG_GBM
static void dbus_gl_gfx_update(DisplayChangeListener *dcl, static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h) int x, int y, int w, int h)
{ {
@ -242,6 +247,7 @@ static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
ddl->gl_updates++; ddl->gl_updates++;
} }
#endif
static void dbus_gfx_update(DisplayChangeListener *dcl, static void dbus_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h) int x, int y, int w, int h)
@ -296,6 +302,7 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
} }
#ifdef CONFIG_GBM
static void dbus_gl_gfx_switch(DisplayChangeListener *dcl, static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface) struct DisplaySurface *new_surface)
{ {
@ -311,6 +318,7 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
width, height, 0, 0, width, height); width, height, 0, 0, width, height);
} }
} }
#endif
static void dbus_gfx_switch(DisplayChangeListener *dcl, static void dbus_gfx_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface) struct DisplaySurface *new_surface)
@ -339,14 +347,13 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
GVariant *v_data = NULL; GVariant *v_data = NULL;
cursor_get(c);
v_data = g_variant_new_from_data( v_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"), G_VARIANT_TYPE("ay"),
c->data, c->data,
c->width * c->height * 4, c->width * c->height * 4,
TRUE, TRUE,
(GDestroyNotify)cursor_put, (GDestroyNotify)cursor_unref,
c); cursor_ref(c));
qemu_dbus_display1_listener_call_cursor_define( qemu_dbus_display1_listener_call_cursor_define(
ddl->proxy, ddl->proxy,
@ -362,6 +369,7 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
NULL); NULL);
} }
#ifdef CONFIG_GBM
const DisplayChangeListenerOps dbus_gl_dcl_ops = { const DisplayChangeListenerOps dbus_gl_dcl_ops = {
.dpy_name = "dbus-gl", .dpy_name = "dbus-gl",
.dpy_gfx_update = dbus_gl_gfx_update, .dpy_gfx_update = dbus_gl_gfx_update,
@ -379,6 +387,7 @@ const DisplayChangeListenerOps dbus_gl_dcl_ops = {
.dpy_gl_release_dmabuf = dbus_release_dmabuf, .dpy_gl_release_dmabuf = dbus_release_dmabuf,
.dpy_gl_update = dbus_scanout_update, .dpy_gl_update = dbus_scanout_update,
}; };
#endif
const DisplayChangeListenerOps dbus_dcl_ops = { const DisplayChangeListenerOps dbus_dcl_ops = {
.dpy_name = "dbus", .dpy_name = "dbus",
@ -407,11 +416,12 @@ dbus_display_listener_constructed(GObject *object)
{ {
DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object); DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
ddl->dcl.ops = &dbus_dcl_ops;
#ifdef CONFIG_GBM
if (display_opengl) { if (display_opengl) {
ddl->dcl.ops = &dbus_gl_dcl_ops; ddl->dcl.ops = &dbus_gl_dcl_ops;
} else {
ddl->dcl.ops = &dbus_dcl_ops;
} }
#endif
G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object); G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object);
} }

View file

@ -30,8 +30,10 @@
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "ui/dbus-module.h" #include "ui/dbus-module.h"
#ifdef CONFIG_OPENGL
#include "ui/egl-helpers.h" #include "ui/egl-helpers.h"
#include "ui/egl-context.h" #include "ui/egl-context.h"
#endif
#include "audio/audio.h" #include "audio/audio.h"
#include "audio/audio_int.h" #include "audio/audio_int.h"
#include "qapi/error.h" #include "qapi/error.h"
@ -41,11 +43,14 @@
static DBusDisplay *dbus_display; static DBusDisplay *dbus_display;
#ifdef CONFIG_OPENGL
static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc, static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
QEMUGLParams *params) QEMUGLParams *params)
{ {
#ifdef CONFIG_GBM
eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
qemu_egl_rn_ctx); qemu_egl_rn_ctx);
#endif
return qemu_egl_create_context(dgc, params); return qemu_egl_create_context(dgc, params);
} }
@ -53,7 +58,11 @@ static bool
dbus_is_compatible_dcl(DisplayGLCtx *dgc, dbus_is_compatible_dcl(DisplayGLCtx *dgc,
DisplayChangeListener *dcl) DisplayChangeListener *dcl)
{ {
return dcl->ops == &dbus_gl_dcl_ops || dcl->ops == &dbus_console_dcl_ops; return
#ifdef CONFIG_GBM
dcl->ops == &dbus_gl_dcl_ops ||
#endif
dcl->ops == &dbus_console_dcl_ops;
} }
static void static void
@ -84,6 +93,7 @@ static const DisplayGLCtxOps dbus_gl_ops = {
.dpy_gl_ctx_destroy_texture = dbus_destroy_texture, .dpy_gl_ctx_destroy_texture = dbus_destroy_texture,
.dpy_gl_ctx_update_texture = dbus_update_texture, .dpy_gl_ctx_update_texture = dbus_update_texture,
}; };
#endif
static NotifierList dbus_display_notifiers = static NotifierList dbus_display_notifiers =
NOTIFIER_LIST_INITIALIZER(dbus_display_notifiers); NOTIFIER_LIST_INITIALIZER(dbus_display_notifiers);
@ -112,10 +122,12 @@ dbus_display_init(Object *o)
DBusDisplay *dd = DBUS_DISPLAY(o); DBusDisplay *dd = DBUS_DISPLAY(o);
g_autoptr(GDBusObjectSkeleton) vm = NULL; g_autoptr(GDBusObjectSkeleton) vm = NULL;
#ifdef CONFIG_OPENGL
dd->glctx.ops = &dbus_gl_ops; dd->glctx.ops = &dbus_gl_ops;
if (display_opengl) { if (display_opengl) {
dd->glctx.gls = qemu_gl_init_shader(); dd->glctx.gls = qemu_gl_init_shader();
} }
#endif
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);
@ -152,7 +164,9 @@ 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);
#ifdef CONFIG_OPENGL
g_clear_pointer(&dd->glctx.gls, qemu_gl_fini_shader); g_clear_pointer(&dd->glctx.gls, qemu_gl_fini_shader);
#endif
dbus_display = NULL; dbus_display = NULL;
} }
@ -220,7 +234,7 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
dd->audiodev); dd->audiodev);
return; return;
} }
audio_state->drv->set_dbus_server(audio_state, dd->server); audio_state->drv->set_dbus_server(audio_state, dd->server, dd->p2p);
} }
consoles = g_array_new(FALSE, FALSE, sizeof(guint32)); consoles = g_array_new(FALSE, FALSE, sizeof(guint32));
@ -451,12 +465,11 @@ early_dbus_init(DisplayOptions *opts)
DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF; DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
if (mode != DISPLAYGL_MODE_OFF) { if (mode != DISPLAYGL_MODE_OFF) {
if (egl_rendernode_init(opts->u.dbus.rendernode, mode) < 0) { #ifdef CONFIG_OPENGL
error_report("dbus: render node init failed"); egl_init(opts->u.dbus.rendernode, mode, &error_fatal);
exit(1); #else
} error_report("dbus: GL rendering is not supported");
#endif
display_opengl = 1;
} }
type_register(&dbus_vc_type_info); type_register(&dbus_vc_type_info);

View file

@ -1,7 +1,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "sysemu/sysemu.h" #include "qapi/error.h"
#include "ui/console.h" #include "ui/console.h"
#include "ui/egl-helpers.h" #include "ui/egl-helpers.h"
#include "ui/egl-context.h" #include "ui/egl-context.h"
@ -191,21 +191,21 @@ static const DisplayGLCtxOps eglctx_ops = {
static void early_egl_headless_init(DisplayOptions *opts) static void early_egl_headless_init(DisplayOptions *opts)
{ {
display_opengl = 1; DisplayGLMode mode = DISPLAYGL_MODE_ON;
if (opts->has_gl) {
mode = opts->gl;
}
egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal);
} }
static void egl_headless_init(DisplayState *ds, DisplayOptions *opts) static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
{ {
DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_ON;
QemuConsole *con; QemuConsole *con;
egl_dpy *edpy; egl_dpy *edpy;
int idx; int idx;
if (egl_rendernode_init(opts->u.egl_headless.rendernode, mode) < 0) {
error_report("egl: render node init failed");
exit(1);
}
for (idx = 0;; idx++) { for (idx = 0;; idx++) {
DisplayGLCtx *ctx; DisplayGLCtx *ctx;

View file

@ -19,6 +19,8 @@
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "ui/console.h" #include "ui/console.h"
#include "ui/egl-helpers.h" #include "ui/egl-helpers.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
EGLDisplay *qemu_egl_display; EGLDisplay *qemu_egl_display;
EGLConfig qemu_egl_config; EGLConfig qemu_egl_config;
@ -26,6 +28,48 @@ DisplayGLMode qemu_egl_mode;
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
#if defined(CONFIG_X11) || defined(CONFIG_GBM)
static const char *egl_get_error_string(void)
{
EGLint error = eglGetError();
switch (error) {
case EGL_SUCCESS:
return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
default:
return "Unknown EGL error";
}
}
#endif
static void egl_fb_delete_texture(egl_fb *fb) static void egl_fb_delete_texture(egl_fb *fb)
{ {
if (!fb->delete_texture) { if (!fb->delete_texture) {
@ -438,20 +482,20 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
qemu_egl_display = qemu_egl_get_display(dpy, platform); qemu_egl_display = qemu_egl_get_display(dpy, platform);
if (qemu_egl_display == EGL_NO_DISPLAY) { if (qemu_egl_display == EGL_NO_DISPLAY) {
error_report("egl: eglGetDisplay failed"); error_report("egl: eglGetDisplay failed: %s", egl_get_error_string());
return -1; return -1;
} }
b = eglInitialize(qemu_egl_display, &major, &minor); b = eglInitialize(qemu_egl_display, &major, &minor);
if (b == EGL_FALSE) { if (b == EGL_FALSE) {
error_report("egl: eglInitialize failed"); error_report("egl: eglInitialize failed: %s", egl_get_error_string());
return -1; return -1;
} }
b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API); b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
if (b == EGL_FALSE) { if (b == EGL_FALSE) {
error_report("egl: eglBindAPI failed (%s mode)", error_report("egl: eglBindAPI failed (%s mode): %s",
gles ? "gles" : "core"); gles ? "gles" : "core", egl_get_error_string());
return -1; return -1;
} }
@ -459,8 +503,8 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
gles ? conf_att_gles : conf_att_core, gles ? conf_att_gles : conf_att_core,
&qemu_egl_config, 1, &n); &qemu_egl_config, 1, &n);
if (b == EGL_FALSE || n != 1) { if (b == EGL_FALSE || n != 1) {
error_report("egl: eglChooseConfig failed (%s mode)", error_report("egl: eglChooseConfig failed (%s mode): %s",
gles ? "gles" : "core"); gles ? "gles" : "core", egl_get_error_string());
return -1; return -1;
} }
@ -527,3 +571,25 @@ EGLContext qemu_egl_init_ctx(void)
return ectx; return ectx;
} }
bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
{
ERRP_GUARD();
if (mode == DISPLAYGL_MODE_OFF) {
error_setg(errp, "egl: turning off GL doesn't make sense");
return false;
}
#ifdef CONFIG_GBM
if (egl_rendernode_init(rendernode, mode) < 0) {
error_setg(errp, "egl: render node init failed");
return false;
}
display_opengl = 1;
return true;
#else
error_setg(errp, "egl: not available on this platform");
return false;
#endif
}

View file

@ -83,7 +83,9 @@ if dbus_display
'--interface-prefix', 'org.qemu.', '--interface-prefix', 'org.qemu.',
'--c-namespace', 'QemuDBus', '--c-namespace', 'QemuDBus',
'--generate-c-code', '@BASENAME@']) '--generate-c-code', '@BASENAME@'])
dbus_ss.add(when: [gio, pixman, opengl, gbm], dbus_display1_lib = static_library('dbus-display1', dbus_display1, dependencies: gio)
dbus_display1_dep = declare_dependency(link_with: dbus_display1_lib, include_directories: include_directories('.'))
dbus_ss.add(when: [gio, pixman, dbus_display1_dep],
if_true: [files( if_true: [files(
'dbus-chardev.c', 'dbus-chardev.c',
'dbus-clipboard.c', 'dbus-clipboard.c',
@ -91,7 +93,7 @@ if dbus_display
'dbus-error.c', 'dbus-error.c',
'dbus-listener.c', 'dbus-listener.c',
'dbus.c', 'dbus.c',
), dbus_display1]) ), opengl, gbm])
ui_modules += {'dbus' : dbus_ss} ui_modules += {'dbus' : dbus_ss}
endif endif

View file

@ -58,6 +58,11 @@ static Notifier mouse_mode_notifier;
#define SDL2_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \ #define SDL2_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \
/ SDL2_REFRESH_INTERVAL_BUSY + 1) / SDL2_REFRESH_INTERVAL_BUSY + 1)
/* introduced in SDL 2.0.10 */
#ifndef SDL_HINT_RENDER_BATCHING
#define SDL_HINT_RENDER_BATCHING "SDL_RENDER_BATCHING"
#endif
static void sdl_update_caption(struct sdl2_console *scon); static void sdl_update_caption(struct sdl2_console *scon);
static struct sdl2_console *get_scon_from_window(uint32_t window_id) static struct sdl2_console *get_scon_from_window(uint32_t window_id)
@ -99,9 +104,20 @@ void sdl2_window_create(struct sdl2_console *scon)
surface_width(scon->surface), surface_width(scon->surface),
surface_height(scon->surface), surface_height(scon->surface),
flags); flags);
scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
if (scon->opengl) { if (scon->opengl) {
scon->winctx = SDL_GL_GetCurrentContext(); const char *driver = "opengl";
if (scon->opts->gl == DISPLAYGL_MODE_ES) {
driver = "opengles2";
}
SDL_SetHint(SDL_HINT_RENDER_DRIVER, driver);
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
}
scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
if (scon->opengl) {
scon->winctx = SDL_GL_CreateContext(scon->real_window);
} }
sdl_update_caption(scon); sdl_update_caption(scon);
} }
@ -112,6 +128,8 @@ void sdl2_window_destroy(struct sdl2_console *scon)
return; return;
} }
SDL_GL_DeleteContext(scon->winctx);
scon->winctx = NULL;
SDL_DestroyRenderer(scon->real_renderer); SDL_DestroyRenderer(scon->real_renderer);
scon->real_renderer = NULL; scon->real_renderer = NULL;
SDL_DestroyWindow(scon->real_window); SDL_DestroyWindow(scon->real_window);
@ -841,6 +859,10 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
} }
#endif #endif
if (SDL_GetHintBoolean("QEMU_ENABLE_SDL_LOGGING", SDL_FALSE)) {
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
}
if (SDL_Init(SDL_INIT_VIDEO)) { if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
SDL_GetError()); SDL_GetError());

View file

@ -1,4 +1,3 @@
#version 300 es #version 300 es
in vec2 in_position; in vec2 in_position;

View file

@ -1,4 +1,3 @@
#version 300 es #version 300 es
uniform sampler2D image; uniform sampler2D image;

View file

@ -1,4 +1,3 @@
#version 300 es #version 300 es
in vec2 in_position; in vec2 in_position;

View file

@ -820,12 +820,7 @@ static void qemu_spice_init(void)
"incompatible with -spice port/tls-port"); "incompatible with -spice port/tls-port");
exit(1); exit(1);
} }
if (egl_rendernode_init(qemu_opt_get(opts, "rendernode"), egl_init(qemu_opt_get(opts, "rendernode"), DISPLAYGL_MODE_ON, &error_fatal);
DISPLAYGL_MODE_ON) != 0) {
error_report("Failed to initialize EGL render node for SPICE GL");
exit(1);
}
display_opengl = 1;
spice_opengl = 1; spice_opengl = 1;
} }
#endif #endif

View file

@ -460,11 +460,11 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
if (ssd->cursor) { if (ssd->cursor) {
QEMUCursor *c = ssd->cursor; QEMUCursor *c = ssd->cursor;
assert(ssd->dcl.con); assert(ssd->dcl.con);
cursor_get(c); cursor_ref(c);
qemu_mutex_unlock(&ssd->lock); qemu_mutex_unlock(&ssd->lock);
dpy_cursor_define(ssd->dcl.con, c); dpy_cursor_define(ssd->dcl.con, c);
qemu_mutex_lock(&ssd->lock); qemu_mutex_lock(&ssd->lock);
cursor_put(c); cursor_unref(c);
} }
if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
@ -765,8 +765,8 @@ static void display_mouse_define(DisplayChangeListener *dcl,
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
qemu_mutex_lock(&ssd->lock); qemu_mutex_lock(&ssd->lock);
cursor_get(c); cursor_ref(c);
cursor_put(ssd->cursor); cursor_unref(ssd->cursor);
ssd->cursor = c; ssd->cursor = c;
ssd->hot_x = c->hot_x; ssd->hot_x = c->hot_x;
ssd->hot_y = c->hot_y; ssd->hot_y = c->hot_y;

View file

@ -988,10 +988,10 @@ static void vnc_mouse_set(DisplayChangeListener *dcl,
static int vnc_cursor_define(VncState *vs) static int vnc_cursor_define(VncState *vs)
{ {
QEMUCursor *c = vs->vd->cursor; QEMUCursor *c = qemu_console_get_cursor(vs->vd->dcl.con);
int isize; int isize;
if (!vs->vd->cursor) { if (!c) {
return -1; return -1;
} }
@ -1029,11 +1029,7 @@ static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
VncState *vs; VncState *vs;
cursor_put(vd->cursor);
g_free(vd->cursor_mask); g_free(vd->cursor_mask);
vd->cursor = c;
cursor_get(vd->cursor);
vd->cursor_msize = cursor_get_mono_bpl(c) * c->height; vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
vd->cursor_mask = g_malloc0(vd->cursor_msize); vd->cursor_mask = g_malloc0(vd->cursor_msize);
cursor_get_mono_mask(c, 0, vd->cursor_mask); cursor_get_mono_mask(c, 0, vd->cursor_mask);

View file

@ -159,7 +159,6 @@ struct VncDisplay
QKbdState *kbd; QKbdState *kbd;
QemuMutex mutex; QemuMutex mutex;
QEMUCursor *cursor;
int cursor_msize; int cursor_msize;
uint8_t *cursor_mask; uint8_t *cursor_mask;