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:
commit
35152940b7
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
@ -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')
|
||||||
|
@ -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();
|
||||||
|
74
ui/console.c
74
ui/console.c
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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:
|
||||||
|
@ -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));
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user