UI-related fixes & shareable 2d memory with -display dbus

-----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmcNHtIcHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5SYTD/9fRNrgnZIvIbIGf0kv
 j3LguzwEsfn8eIUbJEIxtDnoS17zX1t981kP9J9ctUM6wnb0iQNYCXeTrF8Xrq0z
 psiPhHGwPyWMdn9SWRfj597ShPn75z340Qve5GUm7clGu2KILh7TqqACH8LzaX+5
 6jqoZc3kqD+PYZHnYAi6v1YFfLIYfj0n6EaO/J4RRRZSrknpgct7jpmqL4wVzTIo
 KYlG5afdUUfhmSIv5ZDpuuEJppdG74K2H+hJKDPIOOQ8/i/IU2EQPJ00ppiOPbET
 nA0+piLGtHQwU24u5kDdbDlGL/y1KBKvGclOtzLQxWNStch5A6hqllNsuIg+0dJW
 MRO2WZ8C7P7LD1eGmtYVZF/NzjnlTW/hbM5i0poPqhfcwbVmlIXjDs8GUfMGfINr
 1MVFGNjxfgadYZ1f6Q/JU/KWPJMR4Ik3C/SmGrRBlfra5YIts0ItDeGgfQIW9JGb
 1CpOng6/3SvW01B6psrPL+wP+6PsK333KPIA77KafOEMyOyEyuSOUrTShXbyXBHc
 r/nLbWw2lZs4U0kgGRQ21+R3huTyw8LnikYpCnGwTWGCpb9NDFYg7z3CRrZW0hWx
 DIWfN7M6YymeYygPUV9Wjo6i4yq4QqWPp7/QXtkSdX3v44/D7NWytKGST+Hwjkpa
 h6U2vrsLdep2m47bnX/dEEP61g==
 =xdt/
 -----END PGP SIGNATURE-----

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

UI-related fixes & shareable 2d memory with -display dbus

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmcNHtIcHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5SYTD/9fRNrgnZIvIbIGf0kv
# j3LguzwEsfn8eIUbJEIxtDnoS17zX1t981kP9J9ctUM6wnb0iQNYCXeTrF8Xrq0z
# psiPhHGwPyWMdn9SWRfj597ShPn75z340Qve5GUm7clGu2KILh7TqqACH8LzaX+5
# 6jqoZc3kqD+PYZHnYAi6v1YFfLIYfj0n6EaO/J4RRRZSrknpgct7jpmqL4wVzTIo
# KYlG5afdUUfhmSIv5ZDpuuEJppdG74K2H+hJKDPIOOQ8/i/IU2EQPJ00ppiOPbET
# nA0+piLGtHQwU24u5kDdbDlGL/y1KBKvGclOtzLQxWNStch5A6hqllNsuIg+0dJW
# MRO2WZ8C7P7LD1eGmtYVZF/NzjnlTW/hbM5i0poPqhfcwbVmlIXjDs8GUfMGfINr
# 1MVFGNjxfgadYZ1f6Q/JU/KWPJMR4Ik3C/SmGrRBlfra5YIts0ItDeGgfQIW9JGb
# 1CpOng6/3SvW01B6psrPL+wP+6PsK333KPIA77KafOEMyOyEyuSOUrTShXbyXBHc
# r/nLbWw2lZs4U0kgGRQ21+R3huTyw8LnikYpCnGwTWGCpb9NDFYg7z3CRrZW0hWx
# DIWfN7M6YymeYygPUV9Wjo6i4yq4QqWPp7/QXtkSdX3v44/D7NWytKGST+Hwjkpa
# h6U2vrsLdep2m47bnX/dEEP61g==
# =xdt/
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 14 Oct 2024 14:38:26 BST
# 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 'ui-pull-request' of https://gitlab.com/marcandre.lureau/qemu:
  audio/pw: Report more accurate error when connecting to PipeWire fails
  tests: add basic -display dbus Map.Unix test
  ui: refactor using a common qemu_pixman_shareable
  virtio-gpu: allocate shareable 2d resources on !win32
  ui/dbus: implement Unix.Map
  ui/dbus: add Listener.Unix.Map interface XML
  ui/dbus: make Listener.Win32.Map win32-specific
  meson: find_program('gdbus-codegen') directly
  ui/surface: allocate shared memory on !win32
  ui/dbus: add trace for can_share_map
  ui/dbus: do not limit to one listener per connection / bus name
  ui/pixman: generalize shared_image_destroy
  util/memfd: report potential errors on free
  ui/dbus: discard pending CursorDefine on new one
  ui/dbus: discard display messages on disable
  ui/dbus: fix filtering all update messages
  ui/win32: fix potential use-after-free with dbus shared memory
  ui/dbus: fix leak on message filtering
  hw/audio/hda: fix memory leak on audio setup
  hw/audio/hda: free timer on exit

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-10-14 17:05:25 +01:00
commit 35152940b7
15 changed files with 446 additions and 174 deletions

View File

@ -769,13 +769,15 @@ qpw_audio_init(Audiodev *dev, Error **errp)
pw->core = pw_context_connect(pw->context, NULL, 0); pw->core = pw_context_connect(pw->context, NULL, 0);
if (pw->core == NULL) { if (pw->core == NULL) {
pw_thread_loop_unlock(pw->thread_loop); pw_thread_loop_unlock(pw->thread_loop);
goto fail_error; error_setg_errno(errp, errno, "Failed to connect to PipeWire instance");
goto fail;
} }
if (pw_core_add_listener(pw->core, &pw->core_listener, if (pw_core_add_listener(pw->core, &pw->core_listener,
&core_events, pw) < 0) { &core_events, pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop); pw_thread_loop_unlock(pw->thread_loop);
goto fail_error; error_setg(errp, "Failed to add PipeWire listener");
goto fail;
} }
if (wait_resync(pw) < 0) { if (wait_resync(pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop); pw_thread_loop_unlock(pw->thread_loop);
@ -785,8 +787,6 @@ qpw_audio_init(Audiodev *dev, Error **errp)
return g_steal_pointer(&pw); return g_steal_pointer(&pw);
fail_error:
error_setg(errp, "Failed to initialize PW context");
fail: fail:
if (pw->thread_loop) { if (pw->thread_loop) {
pw_thread_loop_stop(pw->thread_loop); pw_thread_loop_stop(pw->thread_loop);

View File

@ -472,6 +472,24 @@ static void hda_audio_set_amp(HDAAudioStream *st)
} }
} }
static void hda_close_stream(HDAAudioState *a, HDAAudioStream *st)
{
if (st->node == NULL) {
return;
}
if (a->use_timer) {
timer_free(st->buft);
st->buft = NULL;
}
if (st->output) {
AUD_close_out(&a->card, st->voice.out);
st->voice.out = NULL;
} else {
AUD_close_in(&a->card, st->voice.in);
st->voice.in = NULL;
}
}
static void hda_audio_setup(HDAAudioStream *st) static void hda_audio_setup(HDAAudioStream *st)
{ {
bool use_timer = st->state->use_timer; bool use_timer = st->state->use_timer;
@ -484,6 +502,7 @@ static void hda_audio_setup(HDAAudioStream *st)
trace_hda_audio_format(st->node->name, st->as.nchannels, trace_hda_audio_format(st->node->name, st->as.nchannels,
fmt2name[st->as.fmt], st->as.freq); fmt2name[st->as.fmt], st->as.freq);
hda_close_stream(st->state, st);
if (st->output) { if (st->output) {
if (use_timer) { if (use_timer) {
cb = hda_audio_output_cb; cb = hda_audio_output_cb;
@ -741,23 +760,11 @@ static void hda_audio_init(HDACodecDevice *hda,
static void hda_audio_exit(HDACodecDevice *hda) static void hda_audio_exit(HDACodecDevice *hda)
{ {
HDAAudioState *a = HDA_AUDIO(hda); HDAAudioState *a = HDA_AUDIO(hda);
HDAAudioStream *st;
int i; int i;
dprint(a, 1, "%s\n", __func__); dprint(a, 1, "%s\n", __func__);
for (i = 0; i < ARRAY_SIZE(a->st); i++) { for (i = 0; i < ARRAY_SIZE(a->st); i++) {
st = a->st + i; hda_close_stream(a, a->st + i);
if (st->node == NULL) {
continue;
}
if (a->use_timer) {
timer_del(st->buft);
}
if (st->output) {
AUD_close_out(&a->card, st->voice.out);
} else {
AUD_close_in(&a->card, st->voice.in);
}
} }
AUD_remove_card(&a->card); AUD_remove_card(&a->card);
} }

View File

@ -28,6 +28,7 @@
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/memfd.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
@ -238,16 +239,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
return height * stride; return height * stride;
} }
#ifdef WIN32
static void
win32_pixman_image_destroy(pixman_image_t *image, void *data)
{
HANDLE handle = data;
qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn);
}
#endif
static void virtio_gpu_resource_create_2d(VirtIOGPU *g, static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd) struct virtio_gpu_ctrl_command *cmd)
{ {
@ -294,28 +285,20 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height); res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
if (res->hostmem + g->hostmem < g->conf_max_hostmem) { if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
void *bits = NULL; if (!qemu_pixman_image_new_shareable(
#ifdef WIN32 &res->image,
bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); &res->share_handle,
if (!bits) { "virtio-gpu res",
goto end;
}
#endif
res->image = pixman_image_create_bits(
pformat, pformat,
c2d.width, c2d.width,
c2d.height, c2d.height,
bits, c2d.height ? res->hostmem / c2d.height : 0); c2d.height ? res->hostmem / c2d.height : 0,
#ifdef WIN32 &error_warn)) {
if (res->image) { goto end;
pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
} }
#endif
} }
#ifdef WIN32
end: end:
#endif
if (!res->image) { if (!res->image) {
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"%s: resource creation failed %d %d %d\n", "%s: resource creation failed %d %d %d\n",
@ -686,9 +669,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
/* realloc the surface ptr */ /* realloc the surface ptr */
scanout->ds = qemu_create_displaysurface_pixman(rect); scanout->ds = qemu_create_displaysurface_pixman(rect);
#ifdef WIN32 qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset);
qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
#endif
pixman_image_unref(rect); pixman_image_unref(rect);
dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con, dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
@ -1284,7 +1265,6 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
VirtIOGPU *g = opaque; VirtIOGPU *g = opaque;
struct virtio_gpu_simple_resource *res; struct virtio_gpu_simple_resource *res;
uint32_t resource_id, pformat; uint32_t resource_id, pformat;
void *bits = NULL;
int i; int i;
g->hostmem = 0; g->hostmem = 0;
@ -1311,24 +1291,17 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
} }
res->hostmem = calc_image_hostmem(pformat, res->width, res->height); res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
#ifdef WIN32 if (!qemu_pixman_image_new_shareable(&res->image,
bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); &res->share_handle,
if (!bits) { "virtio-gpu res",
g_free(res);
return -EINVAL;
}
#endif
res->image = pixman_image_create_bits(
pformat, pformat,
res->width, res->height, res->width,
bits, res->height ? res->hostmem / res->height : 0); res->height,
if (!res->image) { res->height ? res->hostmem / res->height : 0,
&error_warn)) {
g_free(res); g_free(res);
return -EINVAL; return -EINVAL;
} }
#ifdef WIN32
pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
#endif
res->addrs = g_new(uint64_t, res->iov_cnt); res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt); res->iov = g_new(struct iovec, res->iov_cnt);
@ -1461,9 +1434,7 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
return -EINVAL; return -EINVAL;
} }
scanout->ds = qemu_create_displaysurface_pixman(res->image); scanout->ds = qemu_create_displaysurface_pixman(res->image);
#ifdef WIN32 qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0);
qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
#endif
dpy_gfx_replace_surface(scanout->con, scanout->ds); dpy_gfx_replace_surface(scanout->con, scanout->ds);
} }

View File

@ -51,9 +51,7 @@ struct virtio_gpu_simple_resource {
unsigned int iov_cnt; unsigned int iov_cnt;
uint32_t scanout_bitmask; uint32_t scanout_bitmask;
pixman_image_t *image; pixman_image_t *image;
#ifdef WIN32 qemu_pixman_shareable share_handle;
HANDLE handle;
#endif
uint64_t hostmem; uint64_t hostmem;
uint64_t blob_size; uint64_t blob_size;

View File

@ -12,6 +12,8 @@
#include "pixman-minimal.h" #include "pixman-minimal.h"
#endif #endif
#include "qapi/error.h"
/* /*
* pixman image formats are defined to be native endian, * pixman image formats are defined to be native endian,
* that means host byte order on qemu. So we go define * that means host byte order on qemu. So we go define
@ -97,6 +99,28 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
void qemu_pixman_image_unref(pixman_image_t *image); void qemu_pixman_image_unref(pixman_image_t *image);
#ifdef WIN32
typedef HANDLE qemu_pixman_shareable;
#define SHAREABLE_NONE (NULL)
#define SHAREABLE_TO_PTR(handle) (handle)
#define PTR_TO_SHAREABLE(ptr) (ptr)
#else
typedef int qemu_pixman_shareable;
#define SHAREABLE_NONE (-1)
#define SHAREABLE_TO_PTR(handle) GINT_TO_POINTER(handle)
#define PTR_TO_SHAREABLE(ptr) GPOINTER_TO_INT(ptr)
#endif
bool qemu_pixman_image_new_shareable(
pixman_image_t **image,
qemu_pixman_shareable *handle,
const char *name,
pixman_format_code_t format,
int width,
int height,
int rowstride_bytes,
Error **errp);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref)
#endif /* QEMU_PIXMAN_H */ #endif /* QEMU_PIXMAN_H */

View File

@ -23,10 +23,8 @@ typedef struct DisplaySurface {
GLenum gltype; GLenum gltype;
GLuint texture; GLuint texture;
#endif #endif
#ifdef WIN32 qemu_pixman_shareable share_handle;
HANDLE handle; uint32_t share_handle_offset;
uint32_t handle_offset;
#endif
} DisplaySurface; } DisplaySurface;
PixelFormat qemu_default_pixelformat(int bpp); PixelFormat qemu_default_pixelformat(int bpp);
@ -37,10 +35,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image); DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
DisplaySurface *qemu_create_placeholder_surface(int w, int h, DisplaySurface *qemu_create_placeholder_surface(int w, int h,
const char *msg); const char *msg);
#ifdef WIN32
void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
HANDLE h, uint32_t offset); qemu_pixman_shareable handle,
#endif uint32_t offset);
DisplaySurface *qemu_create_displaysurface(int width, int height); DisplaySurface *qemu_create_displaysurface(int width, int height);
void qemu_free_displaysurface(DisplaySurface *surface); void qemu_free_displaysurface(DisplaySurface *surface);

View File

@ -1037,7 +1037,7 @@ if not get_option('gio').auto() or have_system
gio = not_found gio = not_found
endif endif
if gio.found() if gio.found()
gdbus_codegen = find_program(gio.get_variable('gdbus_codegen'), gdbus_codegen = find_program('gdbus-codegen',
required: get_option('gio')) required: get_option('gio'))
gio_unix = dependency('gio-unix-2.0', required: get_option('gio'), gio_unix = dependency('gio-unix-2.0', required: get_option('gio'),
method: 'pkg-config') method: 'pkg-config')

View File

@ -2,9 +2,14 @@
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "qemu/dbus.h" #include "qemu/dbus.h"
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "glib.h"
#include "glibconfig.h"
#include <gio/gio.h> #include <gio/gio.h>
#include <gio/gunixfdlist.h> #include <gio/gunixfdlist.h>
#include "libqtest.h" #include "libqtest.h"
#ifndef WIN32
#include <sys/mman.h>
#endif
#include "ui/dbus-display1.h" #include "ui/dbus-display1.h"
static GDBusConnection* static GDBusConnection*
@ -82,6 +87,7 @@ typedef struct TestDBusConsoleRegister {
GThread *thread; GThread *thread;
GDBusConnection *listener_conn; GDBusConnection *listener_conn;
GDBusObjectManagerServer *server; GDBusObjectManagerServer *server;
bool with_map;
} TestDBusConsoleRegister; } TestDBusConsoleRegister;
static gboolean listener_handle_scanout( static gboolean listener_handle_scanout(
@ -94,13 +100,49 @@ static gboolean listener_handle_scanout(
GVariant *arg_data, GVariant *arg_data,
TestDBusConsoleRegister *test) TestDBusConsoleRegister *test)
{ {
if (!test->with_map) {
g_main_loop_quit(test->loop); g_main_loop_quit(test->loop);
}
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
#ifndef WIN32
static gboolean listener_handle_scanout_map(
QemuDBusDisplay1ListenerUnixMap *object,
GDBusMethodInvocation *invocation,
GUnixFDList *fd_list,
GVariant *arg_handle,
guint arg_offset,
guint arg_width,
guint arg_height,
guint arg_stride,
guint arg_pixman_format,
TestDBusConsoleRegister *test)
{
int fd = -1;
gint32 handle = g_variant_get_handle(arg_handle);
g_autoptr(GError) error = NULL;
void *addr = NULL;
size_t len = arg_height * arg_stride;
g_assert_cmpuint(g_unix_fd_list_get_length(fd_list), ==, 1);
fd = g_unix_fd_list_get(fd_list, handle, &error);
g_assert_no_error(error);
addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, arg_offset);
g_assert_no_errno(addr == MAP_FAILED ? -1 : 0);
g_assert_no_errno(munmap(addr, len));
g_main_loop_quit(test->loop);
close(fd);
return DBUS_METHOD_INVOCATION_HANDLED;
}
#endif
static void static void
test_dbus_console_setup_listener(TestDBusConsoleRegister *test) test_dbus_console_setup_listener(TestDBusConsoleRegister *test, bool with_map)
{ {
g_autoptr(GDBusObjectSkeleton) listener = NULL; g_autoptr(GDBusObjectSkeleton) listener = NULL;
g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL; g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL;
@ -114,6 +156,25 @@ test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
NULL); NULL);
g_dbus_object_skeleton_add_interface(listener, g_dbus_object_skeleton_add_interface(listener,
G_DBUS_INTERFACE_SKELETON(iface)); G_DBUS_INTERFACE_SKELETON(iface));
if (with_map) {
#ifdef WIN32
g_test_skip("map test lacking on win32");
return;
#else
g_autoptr(QemuDBusDisplay1ListenerUnixMapSkeleton) iface_map =
QEMU_DBUS_DISPLAY1_LISTENER_UNIX_MAP_SKELETON(
qemu_dbus_display1_listener_unix_map_skeleton_new());
g_object_connect(iface_map,
"signal::handle-scanout-map", listener_handle_scanout_map, test,
NULL);
g_dbus_object_skeleton_add_interface(listener,
G_DBUS_INTERFACE_SKELETON(iface_map));
g_object_set(iface, "interfaces",
(const gchar *[]) { "org.qemu.Display1.Listener.Unix.Map", NULL },
NULL);
#endif
}
g_dbus_object_manager_server_export(test->server, listener); g_dbus_object_manager_server_export(test->server, listener);
g_dbus_object_manager_server_set_connection(test->server, g_dbus_object_manager_server_set_connection(test->server,
test->listener_conn); test->listener_conn);
@ -145,7 +206,7 @@ test_dbus_console_registered(GObject *source_object,
g_assert_no_error(err); g_assert_no_error(err);
test->listener_conn = g_thread_join(test->thread); test->listener_conn = g_thread_join(test->thread);
test_dbus_console_setup_listener(test); test_dbus_console_setup_listener(test, test->with_map);
} }
static gpointer static gpointer
@ -155,7 +216,7 @@ test_dbus_p2p_server_setup_thread(gpointer data)
} }
static void static void
test_dbus_display_console(void) test_dbus_display_console(const void* data)
{ {
g_autoptr(GError) err = NULL; g_autoptr(GError) err = NULL;
g_autoptr(GDBusConnection) conn = NULL; g_autoptr(GDBusConnection) conn = NULL;
@ -163,7 +224,7 @@ test_dbus_display_console(void)
g_autoptr(GMainLoop) loop = NULL; g_autoptr(GMainLoop) loop = NULL;
QTestState *qts = NULL; QTestState *qts = NULL;
int pair[2]; int pair[2];
TestDBusConsoleRegister test = { 0, }; TestDBusConsoleRegister test = { 0, .with_map = GPOINTER_TO_INT(data) };
#ifdef WIN32 #ifdef WIN32
WSAPROTOCOL_INFOW info; WSAPROTOCOL_INFOW info;
g_autoptr(GVariant) listener = NULL; g_autoptr(GVariant) listener = NULL;
@ -299,7 +360,8 @@ main(int argc, char **argv)
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/dbus-display/vm", test_dbus_display_vm); qtest_add_func("/dbus-display/vm", test_dbus_display_vm);
qtest_add_func("/dbus-display/console", test_dbus_display_console); qtest_add_data_func("/dbus-display/console", GINT_TO_POINTER(false), test_dbus_display_console);
qtest_add_data_func("/dbus-display/console/map", GINT_TO_POINTER(true), test_dbus_display_console);
qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard); qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard);
return g_test_run(); return g_test_run();

View File

@ -37,6 +37,7 @@
#include "trace.h" #include "trace.h"
#include "exec/memory.h" #include "exec/memory.h"
#include "qom/object.h" #include "qom/object.h"
#include "qemu/memfd.h"
#include "console-priv.h" #include "console-priv.h"
@ -452,60 +453,26 @@ qemu_graphic_console_init(Object *obj)
{ {
} }
#ifdef WIN32 void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, qemu_pixman_shareable handle,
HANDLE h, uint32_t offset) uint32_t offset)
{ {
assert(!surface->handle); assert(surface->share_handle == SHAREABLE_NONE);
surface->share_handle = handle;
surface->share_handle_offset = offset;
surface->handle = h;
surface->handle_offset = offset;
} }
static void
win32_pixman_image_destroy(pixman_image_t *image, void *data)
{
DisplaySurface *surface = data;
if (!surface->handle) {
return;
}
assert(surface->handle_offset == 0);
qemu_win32_map_free(
pixman_image_get_data(surface->image),
surface->handle,
&error_warn
);
}
#endif
DisplaySurface *qemu_create_displaysurface(int width, int height) DisplaySurface *qemu_create_displaysurface(int width, int height)
{ {
DisplaySurface *surface;
void *bits = NULL;
#ifdef WIN32
HANDLE handle = NULL;
#endif
trace_displaysurface_create(width, height); trace_displaysurface_create(width, height);
#ifdef WIN32 return qemu_create_displaysurface_from(
bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
#endif
surface = qemu_create_displaysurface_from(
width, height, width, height,
PIXMAN_x8r8g8b8, PIXMAN_x8r8g8b8,
width * 4, bits width * 4, NULL
); );
surface->flags = QEMU_ALLOCATED_FLAG;
#ifdef WIN32
qemu_displaysurface_win32_set_handle(surface, handle, 0);
#endif
return surface;
} }
DisplaySurface *qemu_create_displaysurface_from(int width, int height, DisplaySurface *qemu_create_displaysurface_from(int width, int height,
@ -515,15 +482,25 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
DisplaySurface *surface = g_new0(DisplaySurface, 1); DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_from(surface, width, height, format); trace_displaysurface_create_from(surface, width, height, format);
surface->share_handle = SHAREABLE_NONE;
if (data) {
surface->image = pixman_image_create_bits(format, surface->image = pixman_image_create_bits(format,
width, height, width, height,
(void *)data, linesize); (void *)data, linesize);
assert(surface->image != NULL); } else {
#ifdef WIN32 qemu_pixman_image_new_shareable(&surface->image,
pixman_image_set_destroy_function(surface->image, &surface->share_handle,
win32_pixman_image_destroy, surface); "displaysurface",
#endif format,
width,
height,
linesize,
&error_abort);
surface->flags = QEMU_ALLOCATED_FLAG;
}
assert(surface->image != NULL);
return surface; return surface;
} }
@ -532,6 +509,7 @@ DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
DisplaySurface *surface = g_new0(DisplaySurface, 1); DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_pixman(surface); trace_displaysurface_create_pixman(surface);
surface->share_handle = SHAREABLE_NONE;
surface->image = pixman_image_ref(image); surface->image = pixman_image_ref(image);
return surface; return surface;

View File

@ -41,7 +41,7 @@ struct _DBusDisplayConsole {
DisplayChangeListener dcl; DisplayChangeListener dcl;
DBusDisplay *display; DBusDisplay *display;
GHashTable *listeners; GPtrArray *listeners;
QemuDBusDisplay1Console *iface; QemuDBusDisplay1Console *iface;
QemuDBusDisplay1Keyboard *iface_kbd; QemuDBusDisplay1Keyboard *iface_kbd;
@ -142,8 +142,7 @@ dbus_display_console_init(DBusDisplayConsole *object)
{ {
DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object); DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
ddc->listeners = g_hash_table_new_full(g_str_hash, g_str_equal, ddc->listeners = g_ptr_array_new_with_free_func(g_object_unref);
NULL, g_object_unref);
ddc->dcl.ops = &dbus_console_dcl_ops; ddc->dcl.ops = &dbus_console_dcl_ops;
} }
@ -157,7 +156,7 @@ dbus_display_console_dispose(GObject *object)
g_clear_object(&ddc->iface_mouse); g_clear_object(&ddc->iface_mouse);
g_clear_object(&ddc->iface_kbd); g_clear_object(&ddc->iface_kbd);
g_clear_object(&ddc->iface); g_clear_object(&ddc->iface);
g_clear_pointer(&ddc->listeners, g_hash_table_unref); g_clear_pointer(&ddc->listeners, g_ptr_array_unref);
g_clear_pointer(&ddc->kbd, qkbd_state_free); g_clear_pointer(&ddc->kbd, qkbd_state_free);
G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object); G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object);
@ -179,7 +178,7 @@ listener_vanished_cb(DBusDisplayListener *listener)
trace_dbus_listener_vanished(name); trace_dbus_listener_vanished(name);
g_hash_table_remove(ddc->listeners, name); g_ptr_array_remove_fast(ddc->listeners, listener);
qkbd_state_lift_all_keys(ddc->kbd); qkbd_state_lift_all_keys(ddc->kbd);
} }
@ -267,16 +266,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
DBusDisplayListener *listener; DBusDisplayListener *listener;
int fd; int fd;
if (sender && g_hash_table_contains(ddc->listeners, sender)) {
g_dbus_method_invocation_return_error(
invocation,
DBUS_DISPLAY_ERROR,
DBUS_DISPLAY_ERROR_INVALID,
"`%s` is already registered!",
sender);
return DBUS_METHOD_INVOCATION_HANDLED;
}
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) { if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
@ -331,9 +320,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
g_hash_table_insert(ddc->listeners, g_ptr_array_add(ddc->listeners, listener);
(gpointer)dbus_display_listener_get_bus_name(listener),
listener);
g_object_connect(listener_conn, g_object_connect(listener_conn,
"swapped-signal::closed", listener_vanished_cb, listener, "swapped-signal::closed", listener_vanished_cb, listener,
NULL); NULL);

View File

@ -469,6 +469,53 @@
<property name="Interfaces" type="as" access="read"/> <property name="Interfaces" type="as" access="read"/>
</interface> </interface>
<!--
org.qemu.Display1.Listener.Unix.Map:
This optional client-side interface can complement
org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for
Unix-specific shared memory scanouts.
-->
<?if $(env.HOST_OS) != windows?>
<interface name="org.qemu.Display1.Listener.Unix.Map">
<!--
ScanoutMap:
@handle: the shared map FD.
@offset: mapping offset, in bytes.
@width: display width, in pixels.
@height: display height, in pixels.
@stride: stride, in bytes.
@pixman_format: image format (ex: ``PIXMAN_X8R8G8B8``).
Resize and update the display content with a shared map.
-->
<method name="ScanoutMap">
<arg type="h" name="handle" direction="in"/>
<arg type="u" name="offset" direction="in"/>
<arg type="u" name="width" direction="in"/>
<arg type="u" name="height" direction="in"/>
<arg type="u" name="stride" direction="in"/>
<arg type="u" name="pixman_format" direction="in"/>
</method>
<!--
UpdateMap:
@x: the X update position, in pixels.
@y: the Y update position, in pixels.
@width: the update width, in pixels.
@height: the update height, in pixels.
Update the display content with the current shared map and the given region.
-->
<method name="UpdateMap">
<arg type="i" name="x" direction="in"/>
<arg type="i" name="y" direction="in"/>
<arg type="i" name="width" direction="in"/>
<arg type="i" name="height" direction="in"/>
</method>
</interface>
<?endif?>
<!-- <!--
org.qemu.Display1.Listener.Win32.Map: org.qemu.Display1.Listener.Win32.Map:
@ -476,6 +523,7 @@
org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
specific shared memory scanouts. specific shared memory scanouts.
--> -->
<?if $(env.HOST_OS) == windows?>
<interface name="org.qemu.Display1.Listener.Win32.Map"> <interface name="org.qemu.Display1.Listener.Win32.Map">
<!-- <!--
ScanoutMap: ScanoutMap:
@ -513,6 +561,7 @@
<arg type="i" name="height" direction="in"/> <arg type="i" name="height" direction="in"/>
</method> </method>
</interface> </interface>
<?endif?>
<!-- <!--
org.qemu.Display1.Listener.Win32.D3d11: org.qemu.Display1.Listener.Win32.D3d11:

View File

@ -26,6 +26,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "dbus.h" #include "dbus.h"
#include "glib.h"
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
#include <gio/gunixfdlist.h> #include <gio/gunixfdlist.h>
#endif #endif
@ -82,10 +83,13 @@ struct _DBusDisplayListener {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
egl_fb fb; egl_fb fb;
#endif #endif
#else /* !WIN32 */
QemuDBusDisplay1ListenerUnixMap *map_proxy;
#endif #endif
guint dbus_filter; guint dbus_filter;
guint32 out_serial_to_discard; guint32 display_serial_to_discard;
guint32 cursor_serial_to_discard;
}; };
G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT) G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
@ -93,10 +97,20 @@ G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
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);
static void ddl_discard_pending_messages(DBusDisplayListener *ddl) static void ddl_discard_display_messages(DBusDisplayListener *ddl)
{ {
ddl->out_serial_to_discard = g_dbus_connection_get_last_serial( guint32 serial = g_dbus_connection_get_last_serial(
g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy))); g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
g_atomic_int_set(&ddl->display_serial_to_discard, serial);
}
static void ddl_discard_cursor_messages(DBusDisplayListener *ddl)
{
guint32 serial = g_dbus_connection_get_last_serial(
g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
g_atomic_int_set(&ddl->cursor_serial_to_discard, serial);
} }
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
@ -104,6 +118,8 @@ static void dbus_scanout_disable(DisplayChangeListener *dcl)
{ {
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_call_disable( qemu_dbus_display1_listener_call_disable(
ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
} }
@ -290,7 +306,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
return; return;
} }
ddl_discard_pending_messages(ddl); ddl_discard_display_messages(ddl);
width = qemu_dmabuf_get_width(dmabuf); width = qemu_dmabuf_get_width(dmabuf);
height = qemu_dmabuf_get_height(dmabuf); height = qemu_dmabuf_get_height(dmabuf);
@ -320,13 +336,13 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
return true; return true;
} }
if (!ddl->can_share_map || !ddl->ds->handle) { if (!ddl->can_share_map || !ddl->ds->share_handle) {
return false; return false;
} }
success = DuplicateHandle( success = DuplicateHandle(
GetCurrentProcess(), GetCurrentProcess(),
ddl->ds->handle, ddl->ds->share_handle,
ddl->peer_process, ddl->peer_process,
&target_handle, &target_handle,
FILE_MAP_READ | SECTION_QUERY, FILE_MAP_READ | SECTION_QUERY,
@ -338,12 +354,12 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
return false; return false;
} }
ddl_discard_pending_messages(ddl); ddl_discard_display_messages(ddl);
if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync( if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
ddl->map_proxy, ddl->map_proxy,
GPOINTER_TO_UINT(target_handle), GPOINTER_TO_UINT(target_handle),
ddl->ds->handle_offset, ddl->ds->share_handle_offset,
surface_width(ddl->ds), surface_width(ddl->ds),
surface_height(ddl->ds), surface_height(ddl->ds),
surface_stride(ddl->ds), surface_stride(ddl->ds),
@ -401,7 +417,7 @@ dbus_scanout_share_d3d_texture(
return false; return false;
} }
ddl_discard_pending_messages(ddl); ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d( qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
ddl->d3d11_proxy, ddl->d3d11_proxy,
@ -427,6 +443,51 @@ dbus_scanout_share_d3d_texture(
return true; return true;
} }
#endif /* CONFIG_OPENGL */ #endif /* CONFIG_OPENGL */
#else /* !WIN32 */
static bool dbus_scanout_map(DBusDisplayListener *ddl)
{
g_autoptr(GError) err = NULL;
g_autoptr(GUnixFDList) fd_list = NULL;
if (ddl->ds_share == SHARE_KIND_MAPPED) {
return true;
}
if (!ddl->can_share_map || ddl->ds->share_handle == SHAREABLE_NONE) {
return false;
}
ddl_discard_display_messages(ddl);
fd_list = g_unix_fd_list_new();
if (g_unix_fd_list_append(fd_list, ddl->ds->share_handle, &err) != 0) {
g_debug("Failed to setup scanout map fdlist: %s", err->message);
ddl->can_share_map = false;
return false;
}
if (!qemu_dbus_display1_listener_unix_map_call_scanout_map_sync(
ddl->map_proxy,
g_variant_new_handle(0),
ddl->ds->share_handle_offset,
surface_width(ddl->ds),
surface_height(ddl->ds),
surface_stride(ddl->ds),
surface_format(ddl->ds),
G_DBUS_CALL_FLAGS_NONE,
DBUS_DEFAULT_TIMEOUT,
fd_list,
NULL,
NULL,
&err)) {
g_debug("Failed to call ScanoutMap: %s", err->message);
ddl->can_share_map = false;
return false;
}
ddl->ds_share = SHARE_KIND_MAPPED;
return true;
}
#endif /* WIN32 */ #endif /* WIN32 */
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
@ -497,6 +558,8 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
return; return;
} }
ddl_discard_cursor_messages(ddl);
egl_dmabuf_import_texture(dmabuf); egl_dmabuf_import_texture(dmabuf);
texture = qemu_dmabuf_get_texture(dmabuf); texture = qemu_dmabuf_get_texture(dmabuf);
if (!texture) { if (!texture) {
@ -659,7 +722,7 @@ static void ddl_scanout(DBusDisplayListener *ddl)
surface_stride(ddl->ds) * surface_height(ddl->ds), TRUE, surface_stride(ddl->ds) * surface_height(ddl->ds), TRUE,
(GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image)); (GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image));
ddl_discard_pending_messages(ddl); ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_call_scanout( qemu_dbus_display1_listener_call_scanout(
ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds), ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds),
@ -677,16 +740,22 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
trace_dbus_update(x, y, w, h); trace_dbus_update(x, y, w, h);
#ifdef WIN32
if (dbus_scanout_map(ddl)) { if (dbus_scanout_map(ddl)) {
#ifdef WIN32
qemu_dbus_display1_listener_win32_map_call_update_map( qemu_dbus_display1_listener_win32_map_call_update_map(
ddl->map_proxy, ddl->map_proxy,
x, y, w, h, x, y, w, h,
G_DBUS_CALL_FLAGS_NONE, G_DBUS_CALL_FLAGS_NONE,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
#else
qemu_dbus_display1_listener_unix_map_call_update_map(
ddl->map_proxy,
x, y, w, h,
G_DBUS_CALL_FLAGS_NONE,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
#endif
return; return;
} }
#endif
if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) { if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
return ddl_scanout(ddl); return ddl_scanout(ddl);
@ -740,6 +809,8 @@ 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;
ddl_discard_cursor_messages(ddl);
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,
@ -861,7 +932,6 @@ dbus_display_listener_get_console(DBusDisplayListener *ddl)
return ddl->console; return ddl->console;
} }
#ifdef WIN32
static bool static bool
dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface) dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
{ {
@ -876,6 +946,7 @@ dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
return implements; return implements;
} }
#ifdef WIN32
static bool static bool
dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl) dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
{ {
@ -958,10 +1029,11 @@ dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
static void static void
dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl) dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
{ {
#ifdef WIN32
g_autoptr(GError) err = NULL; g_autoptr(GError) err = NULL;
if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) { #ifdef WIN32
if (!dbus_display_listener_implements(
ddl, "org.qemu.Display1.Listener.Win32.Map")) {
return; return;
} }
@ -981,6 +1053,20 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
return; return;
} }
ddl->can_share_map = true;
#else /* !WIN32 */
if (!dbus_display_listener_implements(
ddl, "org.qemu.Display1.Listener.Unix.Map")) {
return;
}
ddl->map_proxy = qemu_dbus_display1_listener_unix_map_proxy_new_sync(
ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
"/org/qemu/Display1/Listener", NULL, &err);
if (!ddl->map_proxy) {
g_debug("Failed to setup Unix map proxy: %s", err->message);
return;
}
ddl->can_share_map = true; ddl->can_share_map = true;
#endif #endif
} }
@ -992,17 +1078,51 @@ dbus_filter(GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data); DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data);
guint32 serial; guint32 serial, discard_serial;
if (incoming) { if (incoming) {
return message; return message;
} }
serial = g_dbus_message_get_serial(message); serial = g_dbus_message_get_serial(message);
if (serial <= ddl->out_serial_to_discard) {
trace_dbus_filter(serial, ddl->out_serial_to_discard); discard_serial = g_atomic_int_get(&ddl->display_serial_to_discard);
if (serial <= discard_serial) {
const char *member = g_dbus_message_get_member(message);
static const char *const display_messages[] = {
"Scanout",
"Update",
#ifdef CONFIG_GBM
"ScanoutDMABUF",
"UpdateDMABUF",
#endif
"ScanoutMap",
"UpdateMap",
"Disable",
NULL,
};
if (g_strv_contains(display_messages, member)) {
trace_dbus_filter(serial, discard_serial);
g_object_unref(message);
return NULL; return NULL;
} }
}
discard_serial = g_atomic_int_get(&ddl->cursor_serial_to_discard);
if (serial <= discard_serial) {
const gchar *member = g_dbus_message_get_member(message);
static const char *const cursor_messages[] = {
"CursorDefine",
NULL
};
if (g_strv_contains(cursor_messages, member)) {
trace_dbus_filter(serial, discard_serial);
g_object_unref(message);
return NULL;
}
}
return message; return message;
} }
@ -1037,6 +1157,7 @@ dbus_display_listener_new(const char *bus_name,
ddl->console = console; ddl->console = console;
dbus_display_listener_setup_shared_map(ddl); dbus_display_listener_setup_shared_map(ddl);
trace_dbus_can_share_map(ddl->can_share_map);
dbus_display_listener_setup_d3d11(ddl); dbus_display_listener_setup_d3d11(ddl);
con = qemu_console_lookup_by_index(dbus_display_console_get_index(console)); con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));

View File

@ -4,7 +4,9 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h"
#include "ui/console.h" #include "ui/console.h"
#include "qemu/memfd.h"
#include "standard-headers/drm/drm_fourcc.h" #include "standard-headers/drm/drm_fourcc.h"
#include "trace.h" #include "trace.h"
@ -267,3 +269,72 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
pixman_image_unref(ibg); pixman_image_unref(ibg);
} }
#endif /* CONFIG_PIXMAN */ #endif /* CONFIG_PIXMAN */
static void *
qemu_pixman_shareable_alloc(const char *name, size_t size,
qemu_pixman_shareable *handle,
Error **errp)
{
#ifdef WIN32
return qemu_win32_map_alloc(size, handle, errp);
#else
return qemu_memfd_alloc(name, size, 0, handle, errp);
#endif
}
static void
qemu_pixman_shareable_free(qemu_pixman_shareable handle,
void *ptr, size_t size)
{
#ifdef WIN32
qemu_win32_map_free(ptr, handle, &error_warn);
#else
qemu_memfd_free(ptr, size, handle);
#endif
}
static void
qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data)
{
qemu_pixman_shareable handle = PTR_TO_SHAREABLE(data);
void *ptr = pixman_image_get_data(image);
size_t size = pixman_image_get_height(image) * pixman_image_get_stride(image);
qemu_pixman_shareable_free(handle, ptr, size);
}
bool
qemu_pixman_image_new_shareable(pixman_image_t **image,
qemu_pixman_shareable *handle,
const char *name,
pixman_format_code_t format,
int width,
int height,
int rowstride_bytes,
Error **errp)
{
ERRP_GUARD();
size_t size = height * rowstride_bytes;
void *bits = NULL;
g_return_val_if_fail(image != NULL, false);
g_return_val_if_fail(handle != NULL, false);
bits = qemu_pixman_shareable_alloc(name, size, handle, errp);
if (!bits) {
return false;
}
*image = pixman_image_create_bits(format, width, height, bits, rowstride_bytes);
if (!*image) {
error_setg(errp, "Failed to allocate image");
qemu_pixman_shareable_free(*handle, bits, size);
return false;
}
pixman_image_set_destroy_function(*image,
qemu_pixman_shared_image_destroy,
SHAREABLE_TO_PTR(*handle));
return true;
}

View File

@ -166,6 +166,7 @@ dbus_clipboard_unregister(const char *bus_name) "peer %s"
dbus_scanout_texture(uint32_t tex_id, bool backing_y_0_top, uint32_t backing_width, uint32_t backing_height, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "tex_id:%u y0top:%d back:%ux%u %u+%u-%ux%u" dbus_scanout_texture(uint32_t tex_id, bool backing_y_0_top, uint32_t backing_width, uint32_t backing_height, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "tex_id:%u y0top:%d back:%ux%u %u+%u-%ux%u"
dbus_gl_gfx_switch(void *p) "surf: %p" dbus_gl_gfx_switch(void *p) "surf: %p"
dbus_filter(unsigned int serial, unsigned int filter) "serial=%u (<= %u)" dbus_filter(unsigned int serial, unsigned int filter) "serial=%u (<= %u)"
dbus_can_share_map(bool share) "can_share_map: %d"
# egl-helpers.c # egl-helpers.c
egl_init_d3d11_device(void *p) "d3d device: %p" egl_init_d3d11_device(void *p) "d3d device: %p"

View File

@ -28,6 +28,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/memfd.h" #include "qemu/memfd.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
@ -149,11 +150,15 @@ err:
void qemu_memfd_free(void *ptr, size_t size, int fd) void qemu_memfd_free(void *ptr, size_t size, int fd)
{ {
if (ptr) { if (ptr) {
munmap(ptr, size); if (munmap(ptr, size) != 0) {
error_report("memfd munmap() failed: %s", strerror(errno));
}
} }
if (fd != -1) { if (fd != -1) {
close(fd); if (close(fd) != 0) {
error_report("memfd close() failed: %s", strerror(errno));
}
} }
} }