All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/33] UI patches
@ 2023-06-27 13:01 marcandre.lureau
  2023-06-27 13:01 ` [PULL 01/33] ui: return NULL when getting cursor without a console marcandre.lureau
                   ` (32 more replies)
  0 siblings, 33 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The following changes since commit 4329d049d5b8d4af71c6b399d64a6d1b98856318:

  Merge tag 'pull-tcg-20230626' of https://gitlab.com/rth7680/qemu into staging (2023-06-26 17:40:38 +0200)

are available in the Git repository at:

  https://gitlab.com/marcandre.lureau/qemu.git tags/ui-pull-request

for you to fetch changes up to b41858bd0a1361fda7ecb2a08b9b07e21d67f57d:

  ui/dbus: use shared D3D11 Texture2D when possible (2023-06-27 12:33:11 +0200)

----------------------------------------------------------------
UI patches

- add dbus multi-touch interface
- add dbus win32 support
- fixes for sdl & gtk display
- fix for win32 stdio chardev

----------------------------------------------------------------

Antonio Caggiano (1):
  ui/sdl2: OpenGL window context

Bilal Elmoussaoui (2):
  ui/touch: Move event handling to a common helper
  ui/dbus: Expose a touch device interface

Dongwon Kim (4):
  virtio-gpu-udmabuf: create udmabuf for blob even when iov_cnt == 1
  ui/gtk: set the area of the scanout texture correctly
  virtio-gpu: OUT_OF_MEMORY if failing to create udmabuf
  ui/gtk: making dmabuf NULL when it's released.

Keqian Zhu via (1):
  virtio-gpu: Optimize 2D resource data transfer

Marc-André Lureau (23):
  ui: return NULL when getting cursor without a console
  egl: no need to lookup EGL functions manually
  ui/egl: export qemu_egl_get_error_string()
  ui/egl: fix make_context_current() callback return value
  ui/dbus: compile without gio/gunixfdlist.h
  scripts: add a XML preprocessor script
  ui/dbus: win32 support
  qtest: add qtest_pid()
  tests: make dbus-display-test work on win32
  ui/dbus: introduce "Interfaces" properties
  console/win32: allocate shareable display surface
  virtio-gpu/win32: allocate shareable 2d resources/images
  ui/dbus: use shared memory when possible on win32
  ui: add egl-headless support on win32
  ui/egl: default to GLES on windows
  ui: add egl_fb_read_rect()
  ui/dbus: add GL support on win32
  ui/dbus: add some GL traces
  virtio-gpu-virgl: teach it to get the QEMU EGL display
  ui/egl: query ANGLE d3d device
  ui: add optional d3d texture pointer to scanout texture
  virtio-gpu-virgl: use D3D11_SHARE_TEXTURE when available
  ui/dbus: use shared D3D11 Texture2D when possible

Vivek Kasireddy (1):
  virtio-gpu: Make non-gl display updates work again when blob=true

Zhang Huasen (1):
  chardev/char-win-stdio: Support VT sequences on Windows 11 host

 MAINTAINERS                     |   1 +
 meson.build                     |  10 +-
 qapi/ui.json                    |   5 +-
 include/hw/virtio/virtio-gpu.h  |   3 +
 include/sysemu/os-win32.h       |   3 +
 include/ui/console.h            |  30 +-
 include/ui/egl-helpers.h        |  11 +-
 include/ui/gtk.h                |   6 +-
 include/ui/sdl2.h               |   3 +-
 tests/qtest/libqtest.h          |   9 +
 ui/dbus.h                       |   6 +
 audio/dbusaudio.c               |  43 ++-
 chardev/char-win-stdio.c        |   2 +-
 hw/display/virtio-gpu-udmabuf.c |   3 +-
 hw/display/virtio-gpu-virgl.c   |  43 ++-
 hw/display/virtio-gpu.c         |  99 ++++--
 tests/qtest/dbus-display-test.c |  43 ++-
 tests/qtest/libqtest.c          |   5 +
 ui/console.c                    | 137 ++++++++-
 ui/dbus-chardev.c               |  20 +-
 ui/dbus-console.c               | 124 +++++++-
 ui/dbus-listener.c              | 527 +++++++++++++++++++++++++++++---
 ui/dbus.c                       |   4 -
 ui/egl-context.c                |  10 +-
 ui/egl-headless.c               |  25 +-
 ui/egl-helpers.c                | 104 +++++--
 ui/gtk-egl.c                    |  16 +-
 ui/gtk-gl-area.c                |   6 +-
 ui/gtk.c                        |  66 +---
 ui/qemu-pixman.c                |   1 +
 ui/sdl2-gl.c                    |   3 +-
 ui/sdl2.c                       |  18 +-
 ui/spice-display.c              |   3 +-
 util/oslib-win32.c              |  33 ++
 scripts/meson.build             |   2 +
 scripts/xml-preprocess-test.py  | 136 +++++++++
 scripts/xml-preprocess.py       | 293 ++++++++++++++++++
 tests/qtest/meson.build         |   2 +-
 ui/dbus-display1.xml            | 285 ++++++++++++++++-
 ui/meson.build                  |  15 +-
 ui/trace-events                 |   9 +-
 util/trace-events               |   4 +
 42 files changed, 1953 insertions(+), 215 deletions(-)
 create mode 100644 scripts/xml-preprocess-test.py
 create mode 100755 scripts/xml-preprocess.py

-- 
2.41.0



^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PULL 01/33] ui: return NULL when getting cursor without a console
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
@ 2023-06-27 13:01 ` marcandre.lureau
  2023-06-27 13:01 ` [PULL 02/33] egl: no need to lookup EGL functions manually marcandre.lureau
                   ` (31 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

VNC may try to get the current cursor even when there are no consoles
and crashes. Simple reproducer is qemu with -nodefaults.

Fixes: (again)
https://gitlab.com/qemu-project/qemu/-/issues/1548

Fixes: commit 385ac97f8 ("ui: keep current cursor with QemuConsole")
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20230428154807.2143652-1-marcandre.lureau@redhat.com>
---
 ui/console.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ui/console.c b/ui/console.c
index e173731e20..7461446e71 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2306,7 +2306,7 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
     if (con == NULL) {
         con = active_console;
     }
-    return con->cursor;
+    return con ? con->cursor : NULL;
 }
 
 bool qemu_console_is_visible(QemuConsole *con)
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 02/33] egl: no need to lookup EGL functions manually
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
  2023-06-27 13:01 ` [PULL 01/33] ui: return NULL when getting cursor without a console marcandre.lureau
@ 2023-06-27 13:01 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 03/33] ui/sdl2: OpenGL window context marcandre.lureau
                   ` (30 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

libepoxy handles loading the function pointer and dispatching the call,
so you don't have to worry about it.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230515132455.1025608-1-marcandre.lureau@redhat.com>
---
 ui/egl-helpers.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 4203163ace..60385c1f48 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -439,10 +439,8 @@ static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native,
 
     /* In practise any EGL 1.5 implementation would support the EXT extension */
     if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) {
-        PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT =
-            (void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
-        if (getPlatformDisplayEXT && platform != 0) {
-            dpy = getPlatformDisplayEXT(platform, native, NULL);
+        if (platform != 0) {
+            dpy = eglGetPlatformDisplayEXT(platform, native, NULL);
         }
     }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 03/33] ui/sdl2: OpenGL window context
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
  2023-06-27 13:01 ` [PULL 01/33] ui: return NULL when getting cursor without a console marcandre.lureau
  2023-06-27 13:01 ` [PULL 02/33] egl: no need to lookup EGL functions manually marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer marcandre.lureau
                   ` (29 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Antonio Caggiano, Gerd Hoffmann,
	Marc-André Lureau

From: Antonio Caggiano <quic_acaggian@quicinc.com>

When OpenGL is enabled, create only the OpenGL context, ignoring the SDL
renderer as it is unused anyway.

Signed-off-by: Antonio Caggiano <quic_acaggian@quicinc.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230612091959.2983-1-quic_acaggian@quicinc.com>
---
 ui/sdl2.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/ui/sdl2.c b/ui/sdl2.c
index 9d703200bf..0d91b555e3 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -113,11 +113,11 @@ void sdl2_window_create(struct sdl2_console *scon)
 
         SDL_SetHint(SDL_HINT_RENDER_DRIVER, driver);
         SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
-    }
-    scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
 
-    if (scon->opengl) {
         scon->winctx = SDL_GL_CreateContext(scon->real_window);
+    } else {
+        /* The SDL renderer is only used by sdl2-2D, when OpenGL is disabled */
+        scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
     }
     sdl_update_caption(scon);
 }
@@ -128,10 +128,14 @@ void sdl2_window_destroy(struct sdl2_console *scon)
         return;
     }
 
-    SDL_GL_DeleteContext(scon->winctx);
-    scon->winctx = NULL;
-    SDL_DestroyRenderer(scon->real_renderer);
-    scon->real_renderer = NULL;
+    if (scon->winctx) {
+        SDL_GL_DeleteContext(scon->winctx);
+        scon->winctx = NULL;
+    }
+    if (scon->real_renderer) {
+        SDL_DestroyRenderer(scon->real_renderer);
+        scon->real_renderer = NULL;
+    }
     SDL_DestroyWindow(scon->real_window);
     scon->real_window = NULL;
 }
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (2 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 03/33] ui/sdl2: OpenGL window context marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 15:04   ` Richard Henderson
  2023-06-27 13:02 ` [PULL 05/33] chardev/char-win-stdio: Support VT sequences on Windows 11 host marcandre.lureau
                   ` (28 subsequent siblings)
  32 siblings, 1 reply; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Keqian Zhu, Michael S. Tsirkin, Gerd Hoffmann

From: Keqian Zhu via <qemu-devel@nongnu.org>

The following points sometimes can reduce much data
to copy:
1. When width matches, we can transfer data with one
call of iov_to_buf().
2. Only the required height need to transfer, not
whole image.

Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230612021358.25068-1-zhukeqian1@huawei.com>
---
 hw/display/virtio-gpu.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 66cddd94d9..af31018ab0 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -438,11 +438,11 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
                                            struct virtio_gpu_ctrl_command *cmd)
 {
     struct virtio_gpu_simple_resource *res;
-    int h;
+    int h, bpp;
     uint32_t src_offset, dst_offset, stride;
-    int bpp;
     pixman_format_code_t format;
     struct virtio_gpu_transfer_to_host_2d t2d;
+    void *img_data;
 
     VIRTIO_GPU_FILL_CMD(t2d);
     virtio_gpu_t2d_bswap(&t2d);
@@ -471,23 +471,23 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
     format = pixman_image_get_format(res->image);
     bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
     stride = pixman_image_get_stride(res->image);
+    img_data = pixman_image_get_data(res->image);
 
-    if (t2d.offset || t2d.r.x || t2d.r.y ||
-        t2d.r.width != pixman_image_get_width(res->image)) {
-        void *img_data = pixman_image_get_data(res->image);
+    if (t2d.r.x || t2d.r.width != pixman_image_get_width(res->image)) {
         for (h = 0; h < t2d.r.height; h++) {
             src_offset = t2d.offset + stride * h;
             dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
 
             iov_to_buf(res->iov, res->iov_cnt, src_offset,
-                       (uint8_t *)img_data
-                       + dst_offset, t2d.r.width * bpp);
+                       (uint8_t *)img_data + dst_offset,
+                       t2d.r.width * bpp);
         }
     } else {
-        iov_to_buf(res->iov, res->iov_cnt, 0,
-                   pixman_image_get_data(res->image),
-                   pixman_image_get_stride(res->image)
-                   * pixman_image_get_height(res->image));
+        src_offset = t2d.offset;
+        dst_offset = t2d.r.y * stride + t2d.r.x * bpp;
+        iov_to_buf(res->iov, res->iov_cnt, src_offset,
+                   (uint8_t *)img_data + dst_offset,
+                   stride * t2d.r.height);
     }
 }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 05/33] chardev/char-win-stdio: Support VT sequences on Windows 11 host
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (3 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 06/33] ui/touch: Move event handling to a common helper marcandre.lureau
                   ` (27 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Zhang Huasen, Marc-André Lureau, Paolo Bonzini

From: Zhang Huasen <huasenzhang@foxmail.com>

If the monitor or the serial port use STDIO as backend on Windows 11 host,
e.g. -nographic options is used, the monitor or the guest Linux do not
response to arrow keys.

When Windows creates a console, ENABLE_VIRTUAL_PROCESS_INPUT is disabled
by default. Arrow keys cannot be retrieved by ReadFile or ReadConsoleInput
functions.

Add ENABLE_VIRTUAL_PROCESS_INPUT to the flag which is passed to SetConsoleMode,
when opening stdio console.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1674

Signed-off-by: Zhang Huasen <huasenzhang@foxmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <tencent_8DA57B405D427A560FD40F8FB0C0B1ADDE09@qq.com>
---
 chardev/char-win-stdio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c
index eb830eabd9..1a18999e78 100644
--- a/chardev/char-win-stdio.c
+++ b/chardev/char-win-stdio.c
@@ -190,7 +190,7 @@ static void qemu_chr_open_stdio(Chardev *chr,
         }
     }
 
-    dwMode |= ENABLE_LINE_INPUT;
+    dwMode |= ENABLE_LINE_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT;
 
     if (is_console) {
         /* set the terminal in raw mode */
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 06/33] ui/touch: Move event handling to a common helper
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (4 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 05/33] chardev/char-win-stdio: Support VT sequences on Windows 11 host marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 07/33] ui/dbus: Expose a touch device interface marcandre.lureau
                   ` (26 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Bilal Elmoussaoui, Gerd Hoffmann,
	Marc-André Lureau

From: Bilal Elmoussaoui <belmouss@redhat.com>

To share code between the GTK and DBus UI bakcends
see the next commit for details

Signed-off-by: Bilal Elmoussaoui <belmouss@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230619095337.9899-2-belmouss@redhat.com>
---
 include/ui/console.h | 15 ++++++++++
 ui/console.c         | 65 ++++++++++++++++++++++++++++++++++++++++++++
 ui/gtk.c             | 61 ++++-------------------------------------
 3 files changed, 85 insertions(+), 56 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index ae5ec466c1..2093e2a3ba 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -5,6 +5,7 @@
 #include "qom/object.h"
 #include "qemu/notify.h"
 #include "qapi/qapi-types-ui.h"
+#include "ui/input.h"
 
 #ifdef CONFIG_OPENGL
 # include <epoxy/gl.h>
@@ -95,6 +96,20 @@ bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl);
 void kbd_put_string_console(QemuConsole *s, const char *str, int len);
 void kbd_put_keysym(int keysym);
 
+/* Touch devices */
+typedef struct touch_slot {
+    int x;
+    int y;
+    int tracking_id;
+} touch_slot;
+
+void console_handle_touch_event(QemuConsole *con,
+                                struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
+                                uint64_t num_slot,
+                                int width, int height,
+                                double x, double y,
+                                InputMultiTouchType type,
+                                Error **errp);
 /* consoles */
 
 #define TYPE_QEMU_CONSOLE "qemu-console"
diff --git a/ui/console.c b/ui/console.c
index 7461446e71..cfaa43e970 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1635,6 +1635,71 @@ static bool console_compatible_with(QemuConsole *con,
     return true;
 }
 
+void console_handle_touch_event(QemuConsole *con,
+                                struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
+                                uint64_t num_slot,
+                                int width, int height,
+                                double x, double y,
+                                InputMultiTouchType type,
+                                Error **errp)
+{
+    struct touch_slot *slot;
+    bool needs_sync = false;
+    int update;
+    int i;
+
+    if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
+        error_setg(errp,
+                   "Unexpected touch slot number: % " PRId64" >= %d",
+                   num_slot, INPUT_EVENT_SLOTS_MAX);
+        return;
+    }
+
+    slot = &touch_slots[num_slot];
+    slot->x = x;
+    slot->y = y;
+
+    if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
+        slot->tracking_id = num_slot;
+    }
+
+    for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
+        if (i == num_slot) {
+            update = type;
+        } else {
+            update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
+        }
+
+        slot = &touch_slots[i];
+
+        if (slot->tracking_id == -1) {
+            continue;
+        }
+
+        if (update == INPUT_MULTI_TOUCH_TYPE_END) {
+            slot->tracking_id = -1;
+            qemu_input_queue_mtt(con, update, i, slot->tracking_id);
+            needs_sync = true;
+        } else {
+            qemu_input_queue_mtt(con, update, i, slot->tracking_id);
+            qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
+            qemu_input_queue_mtt_abs(con,
+                                    INPUT_AXIS_X, (int) slot->x,
+                                    0, width,
+                                    i, slot->tracking_id);
+            qemu_input_queue_mtt_abs(con,
+                                    INPUT_AXIS_Y, (int) slot->y,
+                                    0, height,
+                                    i, slot->tracking_id);
+            needs_sync = true;
+        }
+    }
+
+    if (needs_sync) {
+        qemu_input_event_sync();
+    }
+}
+
 void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
 {
     /* display has opengl support */
diff --git a/ui/gtk.c b/ui/gtk.c
index e50f950f2b..e09e164482 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -130,11 +130,6 @@ typedef struct VCChardev VCChardev;
 DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
                          TYPE_CHARDEV_VC)
 
-struct touch_slot {
-    int x;
-    int y;
-    int tracking_id;
-};
 static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX];
 
 bool gtk_use_gl_area;
@@ -1068,27 +1063,12 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
                                void *opaque)
 {
     VirtualConsole *vc = opaque;
-    struct touch_slot *slot;
     uint64_t num_slot = GPOINTER_TO_UINT(touch->sequence);
-    bool needs_sync = false;
-    int update;
     int type = -1;
-    int i;
-
-    if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
-        warn_report("gtk: unexpected touch slot number: % " PRId64" >= %d\n",
-                    num_slot, INPUT_EVENT_SLOTS_MAX);
-        return FALSE;
-    }
-
-    slot = &touch_slots[num_slot];
-    slot->x = touch->x;
-    slot->y = touch->y;
 
     switch (touch->type) {
     case GDK_TOUCH_BEGIN:
         type = INPUT_MULTI_TOUCH_TYPE_BEGIN;
-        slot->tracking_id = num_slot;
         break;
     case GDK_TOUCH_UPDATE:
         type = INPUT_MULTI_TOUCH_TYPE_UPDATE;
@@ -1099,44 +1079,13 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
         break;
     default:
         warn_report("gtk: unexpected touch event type\n");
+        return FALSE;
     }
 
-    for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
-        if (i == num_slot) {
-            update = type;
-        } else {
-            update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
-        }
-
-        slot = &touch_slots[i];
-
-        if (slot->tracking_id == -1) {
-            continue;
-        }
-
-        if (update == INPUT_MULTI_TOUCH_TYPE_END) {
-            slot->tracking_id = -1;
-            qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id);
-            needs_sync = true;
-        } else {
-            qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id);
-            qemu_input_queue_btn(vc->gfx.dcl.con, INPUT_BUTTON_TOUCH, true);
-            qemu_input_queue_mtt_abs(vc->gfx.dcl.con,
-                                     INPUT_AXIS_X, (int) slot->x,
-                                     0, surface_width(vc->gfx.ds),
-                                     i, slot->tracking_id);
-            qemu_input_queue_mtt_abs(vc->gfx.dcl.con,
-                                     INPUT_AXIS_Y, (int) slot->y,
-                                     0, surface_height(vc->gfx.ds),
-                                     i, slot->tracking_id);
-            needs_sync = true;
-        }
-    }
-
-    if (needs_sync) {
-        qemu_input_event_sync();
-    }
-
+    console_handle_touch_event(vc->gfx.dcl.con, touch_slots,
+                               num_slot, surface_width(vc->gfx.ds),
+                               surface_height(vc->gfx.ds), touch->x,
+                               touch->y, type, &error_warn);
     return TRUE;
 }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 07/33] ui/dbus: Expose a touch device interface
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (5 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 06/33] ui/touch: Move event handling to a common helper marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 08/33] virtio-gpu: Make non-gl display updates work again when blob=true marcandre.lureau
                   ` (25 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Bilal Elmoussaoui, Marc-André Lureau,
	Gerd Hoffmann

From: Bilal Elmoussaoui <belmouss@redhat.com>

So that clients making use of the DBus backend could
send touch events through the new org.qemu.Display1.Touch
interface

Signed-off-by: Bilal Elmoussaoui <belmouss@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230619095337.9899-3-belmouss@redhat.com>
---
 ui/dbus-console.c    | 59 +++++++++++++++++++++++++++++++++++++++++++-
 ui/dbus-display1.xml | 45 +++++++++++++++++++++++++++++++--
 ui/trace-events      |  1 +
 3 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index f77bc49d2e..bc97614fec 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -32,6 +32,8 @@
 
 #include "dbus.h"
 
+static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX];
+
 struct _DBusDisplayConsole {
     GDBusObjectSkeleton parent_instance;
     DisplayChangeListener dcl;
@@ -44,6 +46,7 @@ struct _DBusDisplayConsole {
     QKbdState *kbd;
 
     QemuDBusDisplay1Mouse *iface_mouse;
+    QemuDBusDisplay1MultiTouch *iface_touch;
     gboolean last_set;
     guint last_x;
     guint last_y;
@@ -345,6 +348,46 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc,
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
 
+static gboolean
+dbus_touch_send_event(DBusDisplayConsole *ddc,
+                      GDBusMethodInvocation *invocation,
+                      guint kind, uint64_t num_slot,
+                      double x, double y)
+{
+    Error *error = NULL;
+    int width, height;
+    trace_dbus_touch_send_event(kind, num_slot, x, y);
+
+    if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN &&
+        kind != INPUT_MULTI_TOUCH_TYPE_UPDATE &&
+        kind != INPUT_MULTI_TOUCH_TYPE_CANCEL &&
+        kind != INPUT_MULTI_TOUCH_TYPE_END)
+    {
+        g_dbus_method_invocation_return_error(
+            invocation, DBUS_DISPLAY_ERROR,
+            DBUS_DISPLAY_ERROR_INVALID,
+            "Invalid touch event kind");
+        return DBUS_METHOD_INVOCATION_HANDLED;
+    }
+    width = qemu_console_get_width(ddc->dcl.con, 0);
+    height = qemu_console_get_height(ddc->dcl.con, 0);
+
+    console_handle_touch_event(ddc->dcl.con, touch_slots,
+                               num_slot, width, height,
+                               x, y, kind, &error);
+    if (error != NULL) {
+        g_dbus_method_invocation_return_error(
+            invocation, DBUS_DISPLAY_ERROR,
+            DBUS_DISPLAY_ERROR_INVALID,
+            error_get_pretty(error), NULL);
+        error_free(error);
+    } else {
+        qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch,
+                                                           invocation);
+    }
+    return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
 static gboolean
 dbus_mouse_set_pos(DBusDisplayConsole *ddc,
                    GDBusMethodInvocation *invocation,
@@ -440,7 +483,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
     g_autofree char *label = NULL;
     char device_addr[256] = "";
     DBusDisplayConsole *ddc;
-    int idx;
+    int idx, i;
 
     assert(display);
     assert(con);
@@ -495,6 +538,20 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
     g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
         G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse));
 
+    ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new();
+    g_object_connect(ddc->iface_touch,
+        "swapped-signal::handle-send-event", dbus_touch_send_event, ddc,
+        NULL);
+    qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch,
+                                                 INPUT_EVENT_SLOTS_MAX);
+    g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
+        G_DBUS_INTERFACE_SKELETON(ddc->iface_touch));
+
+    for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) {
+        struct touch_slot *slot = &touch_slots[i];
+        slot->tracking_id = -1;
+    }
+
     register_displaychangelistener(&ddc->dcl);
     ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
     qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index c3b2293376..cc0c9b68bf 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -39,8 +39,9 @@
       "Text" (see :dbus:prop:`Type` and other properties).
 
       Interactions with a console may be done with
-      :dbus:iface:`org.qemu.Display1.Keyboard` and
-      :dbus:iface:`org.qemu.Display1.Mouse` interfaces when available.
+      :dbus:iface:`org.qemu.Display1.Keyboard`,
+      :dbus:iface:`org.qemu.Display1.Mouse` and
+      :dbus:iface:`org.qemu.Display1.MultiTouch` interfaces when available.
   -->
   <interface name="org.qemu.Display1.Console">
     <!--
@@ -236,6 +237,46 @@
     <property name="IsAbsolute" type="b" access="read"/>
   </interface>
 
+  <!--
+      org.qemu.Display1.MultiTouch:
+
+      This interface in implemented on ``/org/qemu/Display1/Console_$id`` (see
+      :dbus:iface:`~org.qemu.Display1.Console` documentation).
+
+      .. _dbus-kind-values:
+
+      **Kind values**::
+
+        Begin       = 0
+        Update      = 1
+        End         = 2
+        Cancel      = 3
+  -->
+  <interface name="org.qemu.Display1.MultiTouch">
+    <!--
+        SendEvent:
+        @kind: The touch event kind
+        @num_slot: The slot number.
+        @x: The x coordinates.
+        @y: The y coordinates.
+
+        Send a touch gesture event.
+    -->
+    <method name="SendEvent">
+      <arg type="u" name="kind" direction="in"/>
+      <arg type="t" name="num_slot" direction="in"/>
+      <arg type="d" name="x" direction="in"/>
+      <arg type="d" name="y" direction="in"/>
+    </method>
+
+    <!--
+        MaxSlots:
+
+        The maximum number of slots.
+    -->
+    <property name="MaxSlots" type="i" access="read"/>
+  </interface>
+
   <!--
       org.qemu.Display1.Listener:
 
diff --git a/ui/trace-events b/ui/trace-events
index 6747361745..138a09cc03 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -154,6 +154,7 @@ dbus_mouse_press(unsigned int button) "button %u"
 dbus_mouse_release(unsigned int button) "button %u"
 dbus_mouse_set_pos(unsigned int x, unsigned int y) "x=%u, y=%u"
 dbus_mouse_rel_motion(int dx, int dy) "dx=%d, dy=%d"
+dbus_touch_send_event(unsigned int kind, uint32_t num_slot, uint32_t x, uint32_t y) "kind=%u, num_slot=%u, x=%d, y=%d"
 dbus_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
 dbus_clipboard_grab_failed(void) ""
 dbus_clipboard_register(const char *bus_name) "peer %s"
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 08/33] virtio-gpu: Make non-gl display updates work again when blob=true
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (6 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 07/33] ui/dbus: Expose a touch device interface marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 09/33] virtio-gpu-udmabuf: create udmabuf for blob even when iov_cnt == 1 marcandre.lureau
                   ` (24 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Vivek Kasireddy, Gerd Hoffmann,
	Marc-André Lureau, Dongwon Kim, Michael S. Tsirkin

From: Vivek Kasireddy <vivek.kasireddy@intel.com>

In the case where the console does not have gl capability, and
if blob is set to true, make sure that the display updates still
work. Commit e86a93f55463 accidentally broke this by misplacing
the return statement (in resource_flush) causing the updates to
be silently ignored.

Fixes: e86a93f55463 ("virtio-gpu: splitting one extended mode guest fb into n-scanouts")
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Dongwon Kim <dongwon.kim@intel.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20230623060454.3749910-1-vivek.kasireddy@intel.com>
---
 hw/display/virtio-gpu.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index af31018ab0..506cda944d 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -498,6 +498,8 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
     struct virtio_gpu_resource_flush rf;
     struct virtio_gpu_scanout *scanout;
     pixman_region16_t flush_region;
+    bool within_bounds = false;
+    bool update_submitted = false;
     int i;
 
     VIRTIO_GPU_FILL_CMD(rf);
@@ -518,13 +520,28 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
                 rf.r.x < scanout->x + scanout->width &&
                 rf.r.x + rf.r.width >= scanout->x &&
                 rf.r.y < scanout->y + scanout->height &&
-                rf.r.y + rf.r.height >= scanout->y &&
-                console_has_gl(scanout->con)) {
-                dpy_gl_update(scanout->con, 0, 0, scanout->width,
-                              scanout->height);
+                rf.r.y + rf.r.height >= scanout->y) {
+                within_bounds = true;
+
+                if (console_has_gl(scanout->con)) {
+                    dpy_gl_update(scanout->con, 0, 0, scanout->width,
+                                  scanout->height);
+                    update_submitted = true;
+                }
             }
         }
-        return;
+
+        if (update_submitted) {
+            return;
+        }
+        if (!within_bounds) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside scanouts"
+                          " bounds for flush %d: %d %d %d %d\n",
+                          __func__, rf.resource_id, rf.r.x, rf.r.y,
+                          rf.r.width, rf.r.height);
+            cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+            return;
+        }
     }
 
     if (!res->blob &&
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 09/33] virtio-gpu-udmabuf: create udmabuf for blob even when iov_cnt == 1
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (7 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 08/33] virtio-gpu: Make non-gl display updates work again when blob=true marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 10/33] ui/gtk: set the area of the scanout texture correctly marcandre.lureau
                   ` (23 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Dongwon Kim, Gerd Hoffmann,
	Marc-André Lureau, Vivek Kasireddy, Michael S. Tsirkin

From: Dongwon Kim <dongwon.kim@intel.com>

There were often cases where a scanout blob sometimes has just 1 entry
that is linked to many pages in it. So just checking whether iov_cnt is 1
is not enough for screening small, non-scanout blobs. Therefore adding
iov_len check as well to make sure it creates an udmabuf only for a scanout
blob, which is at least bigger than one page size.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20230621222704.29932-1-dongwon.kim@intel.com>
---
 hw/display/virtio-gpu-udmabuf.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index 69e2cf0bd6..ef1a740de5 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -132,7 +132,8 @@ void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res)
     void *pdata = NULL;
 
     res->dmabuf_fd = -1;
-    if (res->iov_cnt == 1) {
+    if (res->iov_cnt == 1 &&
+        res->iov[0].iov_len < 4096) {
         pdata = res->iov[0].iov_base;
     } else {
         virtio_gpu_create_udmabuf(res);
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 10/33] ui/gtk: set the area of the scanout texture correctly
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (8 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 09/33] virtio-gpu-udmabuf: create udmabuf for blob even when iov_cnt == 1 marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 17:46   ` Michael Tokarev
  2023-06-27 13:02 ` [PULL 11/33] virtio-gpu: OUT_OF_MEMORY if failing to create udmabuf marcandre.lureau
                   ` (22 subsequent siblings)
  32 siblings, 1 reply; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Dongwon Kim, Gerd Hoffmann,
	Marc-André Lureau, Vivek Kasireddy

From: Dongwon Kim <dongwon.kim@intel.com>

x and y offsets and width and height of the scanout texture
is not correctly configured in case guest scanout frame is
dmabuf.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
Message-ID: <20230621213150.29573-1-dongwon.kim@intel.com>
---
 ui/gtk-egl.c     | 3 ++-
 ui/gtk-gl-area.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 19130041bc..e99e3b0d8c 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -257,7 +257,8 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
 
     gd_egl_scanout_texture(dcl, dmabuf->texture,
                            dmabuf->y0_top, dmabuf->width, dmabuf->height,
-                           0, 0, dmabuf->width, dmabuf->height);
+                           dmabuf->x, dmabuf->y, dmabuf->scanout_width,
+                           dmabuf->scanout_height);
 
     if (dmabuf->allow_fences) {
         vc->gfx.guest_fb.dmabuf = dmabuf;
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index c384a1516b..1605818bd1 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -299,7 +299,8 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
 
     gd_gl_area_scanout_texture(dcl, dmabuf->texture,
                                dmabuf->y0_top, dmabuf->width, dmabuf->height,
-                               0, 0, dmabuf->width, dmabuf->height);
+                               dmabuf->x, dmabuf->y, dmabuf->scanout_width,
+                               dmabuf->scanout_height);
 
     if (dmabuf->allow_fences) {
         vc->gfx.guest_fb.dmabuf = dmabuf;
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 11/33] virtio-gpu: OUT_OF_MEMORY if failing to create udmabuf
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (9 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 10/33] ui/gtk: set the area of the scanout texture correctly marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 12/33] ui/gtk: making dmabuf NULL when it's released marcandre.lureau
                   ` (21 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Dongwon Kim, Gerd Hoffmann,
	Marc-André Lureau, Vivek Kasireddy, Michael S. Tsirkin

From: Dongwon Kim <dongwon.kim@intel.com>

Respond with VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY if it fails to create
an udmabuf for the blob resource.

v2: consolidated return statments and removed an unnecessary style change

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20230627003453.5321-1-dongwon.kim@intel.com>
---
 hw/display/virtio-gpu.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 506cda944d..1f8a5b16c6 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -651,8 +651,10 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
         if (console_has_gl(scanout->con)) {
             if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) {
                 virtio_gpu_update_scanout(g, scanout_id, res, r);
-                return;
+            } else {
+                *error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
             }
+            return;
         }
 
         data = res->blob;
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 12/33] ui/gtk: making dmabuf NULL when it's released.
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (10 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 11/33] virtio-gpu: OUT_OF_MEMORY if failing to create udmabuf marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 13/33] ui/egl: export qemu_egl_get_error_string() marcandre.lureau
                   ` (20 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Dongwon Kim, Gerd Hoffmann,
	Marc-André Lureau, Vivek Kasireddy

From: Dongwon Kim <dongwon.kim@intel.com>

Set vc->gfx.guest_fb.dmabuf to NULL to prevent any further access
to it after the dmabuf is released.

v2: move declaration of vc inside ifdef

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20230627005316.5627-1-dongwon.kim@intel.com>
---
 ui/gtk.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ui/gtk.c b/ui/gtk.c
index e09e164482..8ba41c8f13 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -583,7 +583,12 @@ static void gd_gl_release_dmabuf(DisplayChangeListener *dcl,
                                  QemuDmaBuf *dmabuf)
 {
 #ifdef CONFIG_GBM
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
     egl_dmabuf_release_texture(dmabuf);
+    if (vc->gfx.guest_fb.dmabuf == dmabuf) {
+        vc->gfx.guest_fb.dmabuf = NULL;
+    }
 #endif
 }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 13/33] ui/egl: export qemu_egl_get_error_string()
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (11 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 12/33] ui/gtk: making dmabuf NULL when it's released marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 14/33] ui/egl: fix make_context_current() callback return value marcandre.lureau
                   ` (19 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

It will be used from other units.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-2-marcandre.lureau@redhat.com>
---
 include/ui/egl-helpers.h |  2 ++
 ui/egl-helpers.c         | 12 +++++-------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 53d953ddf4..2cf6633ad2 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -67,4 +67,6 @@ bool qemu_egl_has_dmabuf(void);
 
 bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp);
 
+const char *qemu_egl_get_error_string(void);
+
 #endif /* EGL_HELPERS_H */
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 60385c1f48..26d43e0213 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -28,8 +28,7 @@ DisplayGLMode qemu_egl_mode;
 
 /* ------------------------------------------------------------------ */
 
-#if defined(CONFIG_X11) || defined(CONFIG_GBM)
-static const char *egl_get_error_string(void)
+const char *qemu_egl_get_error_string(void)
 {
     EGLint error = eglGetError();
 
@@ -68,7 +67,6 @@ static const char *egl_get_error_string(void)
         return "Unknown EGL error";
     }
 }
-#endif
 
 static void egl_fb_delete_texture(egl_fb *fb)
 {
@@ -480,20 +478,20 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
 
     qemu_egl_display = qemu_egl_get_display(dpy, platform);
     if (qemu_egl_display == EGL_NO_DISPLAY) {
-        error_report("egl: eglGetDisplay failed: %s", egl_get_error_string());
+        error_report("egl: eglGetDisplay failed: %s", qemu_egl_get_error_string());
         return -1;
     }
 
     b = eglInitialize(qemu_egl_display, &major, &minor);
     if (b == EGL_FALSE) {
-        error_report("egl: eglInitialize failed: %s", egl_get_error_string());
+        error_report("egl: eglInitialize failed: %s", qemu_egl_get_error_string());
         return -1;
     }
 
     b = eglBindAPI(gles ?  EGL_OPENGL_ES_API : EGL_OPENGL_API);
     if (b == EGL_FALSE) {
         error_report("egl: eglBindAPI failed (%s mode): %s",
-                     gles ? "gles" : "core", egl_get_error_string());
+                     gles ? "gles" : "core", qemu_egl_get_error_string());
         return -1;
     }
 
@@ -502,7 +500,7 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
                         &qemu_egl_config, 1, &n);
     if (b == EGL_FALSE || n != 1) {
         error_report("egl: eglChooseConfig failed (%s mode): %s",
-                     gles ? "gles" : "core", egl_get_error_string());
+                     gles ? "gles" : "core", qemu_egl_get_error_string());
         return -1;
     }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 14/33] ui/egl: fix make_context_current() callback return value
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (12 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 13/33] ui/egl: export qemu_egl_get_error_string() marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 15/33] ui/dbus: compile without gio/gunixfdlist.h marcandre.lureau
                   ` (18 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

eglMakeCurrent() returns 1/EGL_TRUE on success. This is not what the
callback expects, where 0 indicates success.

While at it, print the EGL error to ease debugging.

As with virgl_renderer_callbacks, the return value is now checked since
version >= 4:
https://gitlab.freedesktop.org/virgl/virglrenderer/-/commit/7f09e6bf0c6ceea6727bd0049781256a28cab0e5

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-3-marcandre.lureau@redhat.com>
---
 ui/egl-context.c | 10 ++++++++--
 ui/gtk-egl.c     | 10 ++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/ui/egl-context.c b/ui/egl-context.c
index eb5f520fc4..9e0df466f3 100644
--- a/ui/egl-context.c
+++ b/ui/egl-context.c
@@ -1,4 +1,5 @@
 #include "qemu/osdep.h"
+#include "qemu/error-report.h"
 #include "ui/egl-context.h"
 
 QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,
@@ -32,6 +33,11 @@ void qemu_egl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)
 int qemu_egl_make_context_current(DisplayGLCtx *dgc,
                                   QEMUGLContext ctx)
 {
-   return eglMakeCurrent(qemu_egl_display,
-                         EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);
+   if (!eglMakeCurrent(qemu_egl_display,
+                       EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
+        error_report("egl: eglMakeCurrent failed: %s", qemu_egl_get_error_string());
+        return -1;
+   }
+
+   return 0;
 }
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index e99e3b0d8c..64dc0eeec8 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -13,6 +13,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu/main-loop.h"
+#include "qemu/error-report.h"
 
 #include "trace.h"
 
@@ -369,6 +370,11 @@ int gd_egl_make_current(DisplayGLCtx *dgc,
 {
     VirtualConsole *vc = container_of(dgc, VirtualConsole, gfx.dgc);
 
-    return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
-                          vc->gfx.esurface, ctx);
+    if (!eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                        vc->gfx.esurface, ctx)) {
+        error_report("egl: eglMakeCurrent failed: %s", qemu_egl_get_error_string());
+        return -1;
+    }
+
+    return 0;
 }
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 15/33] ui/dbus: compile without gio/gunixfdlist.h
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (13 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 14/33] ui/egl: fix make_context_current() callback return value marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 16/33] scripts: add a XML preprocessor script marcandre.lureau
                   ` (17 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

D-Bus on windows doesn't support fd-passing. Let's isolate the
fdlist-related code as a first step, before adding Windows support,
using another mechanism.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-4-marcandre.lureau@redhat.com>
---
 audio/dbusaudio.c  | 7 +++++++
 ui/dbus-chardev.c  | 6 ++++++
 ui/dbus-console.c  | 8 ++++++++
 ui/dbus-listener.c | 2 ++
 4 files changed, 23 insertions(+)

diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
index fece74f78c..de59467d9e 100644
--- a/audio/dbusaudio.c
+++ b/audio/dbusaudio.c
@@ -29,7 +29,10 @@
 #include "qemu/timer.h"
 #include "qemu/dbus.h"
 
+#ifdef G_OS_UNIX
 #include <gio/gunixfdlist.h>
+#endif
+
 #include "ui/dbus-display1.h"
 
 #define AUDIO_CAP "dbus"
@@ -419,6 +422,7 @@ dbus_audio_fini(void *opaque)
     g_free(da);
 }
 
+#ifdef G_OS_UNIX
 static void
 listener_out_vanished_cb(GDBusConnection *connection,
                          gboolean remote_peer_vanished,
@@ -591,6 +595,7 @@ dbus_audio_register_in_listener(AudioState *s,
     return dbus_audio_register_listener(s, invocation,
                                         fd_list, arg_listener, false);
 }
+#endif
 
 static void
 dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
@@ -605,12 +610,14 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
 
     da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
     da->iface = qemu_dbus_display1_audio_skeleton_new();
+#ifdef G_OS_UNIX
     g_object_connect(da->iface,
                      "swapped-signal::handle-register-in-listener",
                      dbus_audio_register_in_listener, s,
                      "swapped-signal::handle-register-out-listener",
                      dbus_audio_register_out_listener, s,
                      NULL);
+#endif
 
     g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
                                          G_DBUS_INTERFACE_SKELETON(da->iface));
diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c
index 940ef937cd..7154d81a9a 100644
--- a/ui/dbus-chardev.c
+++ b/ui/dbus-chardev.c
@@ -27,7 +27,9 @@
 #include "qemu/config-file.h"
 #include "qemu/option.h"
 
+#ifdef G_OS_UNIX
 #include <gio/gunixfdlist.h>
+#endif
 
 #include "dbus.h"
 
@@ -108,6 +110,7 @@ dbus_chardev_init(DBusDisplay *dpy)
                          dbus_display_chardev_foreach, dpy);
 }
 
+#ifdef G_OS_UNIX
 static gboolean
 dbus_chr_register(
     DBusChardev *dc,
@@ -145,6 +148,7 @@ dbus_chr_register(
     qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
+#endif
 
 static gboolean
 dbus_chr_send_break(
@@ -175,8 +179,10 @@ dbus_chr_open(Chardev *chr, ChardevBackend *backend,
     dc->iface = qemu_dbus_display1_chardev_skeleton_new();
     g_object_set(dc->iface, "name", backend->u.dbus.data->name, NULL);
     g_object_connect(dc->iface,
+#ifdef G_OS_UNIX
                      "swapped-signal::handle-register",
                      dbus_chr_register, dc,
+#endif
                      "swapped-signal::handle-send-break",
                      dbus_chr_send_break, dc,
                      NULL);
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index bc97614fec..d5f6c93637 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -28,7 +28,9 @@
 #include "ui/kbd-state.h"
 #include "trace.h"
 
+#ifdef G_OS_UNIX
 #include <gio/gunixfdlist.h>
+#endif
 
 #include "dbus.h"
 
@@ -163,6 +165,7 @@ dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
     gobject_class->dispose = dbus_display_console_dispose;
 }
 
+#ifdef G_OS_UNIX
 static void
 listener_vanished_cb(DBusDisplayListener *listener)
 {
@@ -174,6 +177,7 @@ listener_vanished_cb(DBusDisplayListener *listener)
     g_hash_table_remove(ddc->listeners, name);
     qkbd_state_lift_all_keys(ddc->kbd);
 }
+#endif
 
 static gboolean
 dbus_console_set_ui_info(DBusDisplayConsole *ddc,
@@ -207,6 +211,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
 
+#ifdef G_OS_UNIX
 static gboolean
 dbus_console_register_listener(DBusDisplayConsole *ddc,
                                GDBusMethodInvocation *invocation,
@@ -282,6 +287,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
     trace_dbus_registered_listener(sender);
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
+#endif
 
 static gboolean
 dbus_kbd_press(DBusDisplayConsole *ddc,
@@ -510,8 +516,10 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
         "device-address", device_addr,
         NULL);
     g_object_connect(ddc->iface,
+#ifdef G_OS_UNIX
         "swapped-signal::handle-register-listener",
         dbus_console_register_listener, ddc,
+#endif
         "swapped-signal::handle-set-uiinfo",
         dbus_console_set_ui_info, ddc,
         NULL);
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 23034eebf9..41597a0078 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -25,7 +25,9 @@
 #include "qemu/error-report.h"
 #include "sysemu/sysemu.h"
 #include "dbus.h"
+#ifdef G_OS_UNIX
 #include <gio/gunixfdlist.h>
+#endif
 
 #ifdef CONFIG_OPENGL
 #include "ui/shader.h"
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 16/33] scripts: add a XML preprocessor script
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (14 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 15/33] ui/dbus: compile without gio/gunixfdlist.h marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 17/33] ui/dbus: win32 support marcandre.lureau
                   ` (16 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, John Snow, Cleber Rosa

From: Marc-André Lureau <marcandre.lureau@redhat.com>

gdbus-codegen doesn't support conditions or pre-processing.

Rather than duplicating D-Bus interfaces for win32 adaptation, let's
have a preprocess step, so we can have platform-specific interfaces.

The python script is based on
https://github.com/peitaosu/XML-Preprocessor, with bug fixes, some
testing and replacing lxml dependency with the built-in xml module.

This preprocessing syntax style is not very common, but is similar to
the one provided by WiX (https://wixtoolset.org/docs/v3/overview/preprocessor/)
or wixl, that we adopted in QEMU for packaging the guest agent.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-5-marcandre.lureau@redhat.com>
---
 MAINTAINERS                    |   1 +
 scripts/meson.build            |   2 +
 scripts/xml-preprocess-test.py | 136 +++++++++++++++
 scripts/xml-preprocess.py      | 293 +++++++++++++++++++++++++++++++++
 4 files changed, 432 insertions(+)
 create mode 100644 scripts/xml-preprocess-test.py
 create mode 100755 scripts/xml-preprocess.py

diff --git a/MAINTAINERS b/MAINTAINERS
index e07746ac7d..21a587ce4b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3202,6 +3202,7 @@ F: docs/interop/dbus*
 F: docs/sphinx/dbus*
 F: docs/sphinx/fakedbusdoc.py
 F: tests/qtest/dbus*
+F: scripts/xml-preprocess*
 
 Seccomp
 M: Daniel P. Berrange <berrange@redhat.com>
diff --git a/scripts/meson.build b/scripts/meson.build
index 1c89e10a76..532277f5a2 100644
--- a/scripts/meson.build
+++ b/scripts/meson.build
@@ -1,3 +1,5 @@
 if stap.found()
   install_data('qemu-trace-stap', install_dir: get_option('bindir'))
 endif
+
+test('xml-preprocess', files('xml-preprocess-test.py'), suite: ['unit'])
diff --git a/scripts/xml-preprocess-test.py b/scripts/xml-preprocess-test.py
new file mode 100644
index 0000000000..dd92579969
--- /dev/null
+++ b/scripts/xml-preprocess-test.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# SPDX-License-Identifier: MIT
+"""Unit tests for xml-preprocess"""
+
+import contextlib
+import importlib
+import os
+import platform
+import subprocess
+import tempfile
+import unittest
+from io import StringIO
+
+xmlpp = importlib.import_module("xml-preprocess")
+
+
+class TestXmlPreprocess(unittest.TestCase):
+    """Tests for xml-preprocess.Preprocessor"""
+
+    def test_preprocess_xml(self):
+        with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file:
+            temp_file.write("<root></root>")
+            temp_file_name = temp_file.name
+        result = xmlpp.preprocess_xml(temp_file_name)
+        self.assertEqual(result, "<root></root>")
+        os.remove(temp_file_name)
+
+    def test_save_xml(self):
+        with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file:
+            temp_file_name = temp_file.name
+            xmlpp.save_xml("<root></root>", temp_file_name)
+        self.assertTrue(os.path.isfile(temp_file_name))
+        os.remove(temp_file_name)
+
+    def test_include(self):
+        with tempfile.NamedTemporaryFile(mode="w", delete=False) as inc_file:
+            inc_file.write("<included>Content from included file</included>")
+            inc_file_name = inc_file.name
+        xml_str = f"<?include {inc_file_name} ?>"
+        expected = "<included>Content from included file</included>"
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess(xml_str)
+        self.assertEqual(result, expected)
+        os.remove(inc_file_name)
+        self.assertRaises(FileNotFoundError, xpp.preprocess, xml_str)
+
+    def test_envvar(self):
+        os.environ["TEST_ENV_VAR"] = "TestValue"
+        xml_str = "<root>$(env.TEST_ENV_VAR)</root>"
+        expected = "<root>TestValue</root>"
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess(xml_str)
+        self.assertEqual(result, expected)
+        self.assertRaises(KeyError, xpp.preprocess, "$(env.UNKNOWN)")
+
+    def test_sys_var(self):
+        xml_str = "<root>$(sys.ARCH)</root>"
+        expected = f"<root>{platform.architecture()[0]}</root>"
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess(xml_str)
+        self.assertEqual(result, expected)
+        self.assertRaises(KeyError, xpp.preprocess, "$(sys.UNKNOWN)")
+
+    def test_cus_var(self):
+        xml_str = "<root>$(var.USER)</root>"
+        expected = "<root></root>"
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess(xml_str)
+        self.assertEqual(result, expected)
+        xml_str = "<?define USER=FOO?><root>$(var.USER)</root>"
+        expected = "<root>FOO</root>"
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess(xml_str)
+        self.assertEqual(result, expected)
+
+    def test_error_warning(self):
+        xml_str = "<root><?warning \"test warn\"?></root>"
+        expected = "<root></root>"
+        xpp = xmlpp.Preprocessor()
+        out = StringIO()
+        with contextlib.redirect_stdout(out):
+            result = xpp.preprocess(xml_str)
+        self.assertEqual(result, expected)
+        self.assertEqual(out.getvalue(), "[Warning]: test warn\n")
+        self.assertRaises(RuntimeError, xpp.preprocess, "<?error \"test\"?>")
+
+    def test_cmd(self):
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess('<root><?cmd "echo hello world"?></root>')
+        self.assertEqual(result, "<root>hello world</root>")
+        self.assertRaises(
+            subprocess.CalledProcessError,
+            xpp.preprocess, '<?cmd "test-unknown-cmd"?>'
+        )
+
+    def test_foreach(self):
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess(
+            '<root><?foreach x in a;b;c?>$(var.x)<?endforeach?></root>'
+        )
+        self.assertEqual(result, "<root>abc</root>")
+
+    def test_if_elseif(self):
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess('<root><?if True?>ok<?endif?></root>')
+        self.assertEqual(result, "<root>ok</root>")
+        result = xpp.preprocess('<root><?if False?>ok<?endif?></root>')
+        self.assertEqual(result, "<root></root>")
+        result = xpp.preprocess('<root><?if True?>ok<?else?>ko<?endif?></root>')
+        self.assertEqual(result, "<root>ok</root>")
+        result = xpp.preprocess('<root><?if False?>ok<?else?>ko<?endif?></root>')
+        self.assertEqual(result, "<root>ko</root>")
+        result = xpp.preprocess(
+            '<root><?if False?>ok<?elseif True?>ok2<?else?>ko<?endif?></root>'
+        )
+        self.assertEqual(result, "<root>ok2</root>")
+        result = xpp.preprocess(
+            '<root><?if False?>ok<?elseif False?>ok<?else?>ko<?endif?></root>'
+        )
+        self.assertEqual(result, "<root>ko</root>")
+
+    def test_ifdef(self):
+        xpp = xmlpp.Preprocessor()
+        result = xpp.preprocess('<root><?ifdef USER?>ok<?else?>ko<?endif?></root>')
+        self.assertEqual(result, "<root>ko</root>")
+        result = xpp.preprocess(
+            '<?define USER=FOO?><root><?ifdef USER?>ok<?else?>ko<?endif?></root>'
+        )
+        self.assertEqual(result, "<root>ok</root>")
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/scripts/xml-preprocess.py b/scripts/xml-preprocess.py
new file mode 100755
index 0000000000..57f1d28912
--- /dev/null
+++ b/scripts/xml-preprocess.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2017-2019 Tony Su
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# SPDX-License-Identifier: MIT
+#
+# Adapted from https://github.com/peitaosu/XML-Preprocessor
+#
+"""This is a XML Preprocessor which can be used to process your XML file before
+you use it, to process conditional statements, variables, iteration
+statements, error/warning, execute command, etc.
+
+## XML Schema
+
+### Include Files
+```
+<?include path/to/file ?>
+```
+
+### Variables
+```
+$(env.EnvironmentVariable)
+
+$(sys.SystemVariable)
+
+$(var.CustomVariable)
+```
+
+### Conditional Statements
+```
+<?if ?>
+
+<?ifdef ?>
+
+<?ifndef ?>
+
+<?else?>
+
+<?elseif ?>
+
+<?endif?>
+```
+
+### Iteration Statements
+```
+<?foreach VARNAME in 1;2;3?>
+    $(var.VARNAME)
+<?endforeach?>
+```
+
+### Errors and Warnings
+```
+<?error "This is error message!" ?>
+
+<?warning "This is warning message!" ?>
+```
+
+### Commands
+```
+<? cmd "echo hello world" ?>
+```
+"""
+
+import os
+import platform
+import re
+import subprocess
+import sys
+from typing import Optional
+from xml.dom import minidom
+
+
+class Preprocessor():
+    """This class holds the XML preprocessing state"""
+
+    def __init__(self):
+        self.sys_vars = {
+            "ARCH": platform.architecture()[0],
+            "SOURCE": os.path.abspath(__file__),
+            "CURRENT": os.getcwd(),
+        }
+        self.cus_vars = {}
+
+    def _pp_include(self, xml_str: str) -> str:
+        include_regex = r"(<\?include([\w\s\\/.:_-]+)\s*\?>)"
+        matches = re.findall(include_regex, xml_str)
+        for group_inc, group_xml in matches:
+            inc_file_path = group_xml.strip()
+            with open(inc_file_path, "r", encoding="utf-8") as inc_file:
+                inc_file_content = inc_file.read()
+                xml_str = xml_str.replace(group_inc, inc_file_content)
+        return xml_str
+
+    def _pp_env_var(self, xml_str: str) -> str:
+        envvar_regex = r"(\$\(env\.(\w+)\))"
+        matches = re.findall(envvar_regex, xml_str)
+        for group_env, group_var in matches:
+            xml_str = xml_str.replace(group_env, os.environ[group_var])
+        return xml_str
+
+    def _pp_sys_var(self, xml_str: str) -> str:
+        sysvar_regex = r"(\$\(sys\.(\w+)\))"
+        matches = re.findall(sysvar_regex, xml_str)
+        for group_sys, group_var in matches:
+            xml_str = xml_str.replace(group_sys, self.sys_vars[group_var])
+        return xml_str
+
+    def _pp_cus_var(self, xml_str: str) -> str:
+        define_regex = r"(<\?define\s*(\w+)\s*=\s*([\w\s\"]+)\s*\?>)"
+        matches = re.findall(define_regex, xml_str)
+        for group_def, group_name, group_var in matches:
+            group_name = group_name.strip()
+            group_var = group_var.strip().strip("\"")
+            self.cus_vars[group_name] = group_var
+            xml_str = xml_str.replace(group_def, "")
+        cusvar_regex = r"(\$\(var\.(\w+)\))"
+        matches = re.findall(cusvar_regex, xml_str)
+        for group_cus, group_var in matches:
+            xml_str = xml_str.replace(
+                group_cus,
+                self.cus_vars.get(group_var, "")
+            )
+        return xml_str
+
+    def _pp_foreach(self, xml_str: str) -> str:
+        foreach_regex = r"(<\?foreach\s+(\w+)\s+in\s+([\w;]+)\s*\?>(.*)<\?endforeach\?>)"
+        matches = re.findall(foreach_regex, xml_str)
+        for group_for, group_name, group_vars, group_text in matches:
+            group_texts = ""
+            for var in group_vars.split(";"):
+                self.cus_vars[group_name] = var
+                group_texts += self._pp_cus_var(group_text)
+            xml_str = xml_str.replace(group_for, group_texts)
+        return xml_str
+
+    def _pp_error_warning(self, xml_str: str) -> str:
+        error_regex = r"<\?error\s*\"([^\"]+)\"\s*\?>"
+        matches = re.findall(error_regex, xml_str)
+        for group_var in matches:
+            raise RuntimeError("[Error]: " + group_var)
+        warning_regex = r"(<\?warning\s*\"([^\"]+)\"\s*\?>)"
+        matches = re.findall(warning_regex, xml_str)
+        for group_wrn, group_var in matches:
+            print("[Warning]: " + group_var)
+            xml_str = xml_str.replace(group_wrn, "")
+        return xml_str
+
+    def _pp_if_eval(self, xml_str: str) -> str:
+        ifelif_regex = (
+            r"(<\?(if|elseif)\s*([^\"\s=<>!]+)\s*([!=<>]+)\s*\"*([^\"=<>!]+)\"*\s*\?>)"
+        )
+        matches = re.findall(ifelif_regex, xml_str)
+        for ifelif, tag, left, operator, right in matches:
+            if "<" in operator or ">" in operator:
+                result = eval(f"{left} {operator} {right}")
+            else:
+                result = eval(f'"{left}" {operator} "{right}"')
+            xml_str = xml_str.replace(ifelif, f"<?{tag} {result}?>")
+        return xml_str
+
+    def _pp_ifdef_ifndef(self, xml_str: str) -> str:
+        ifndef_regex = r"(<\?(ifdef|ifndef)\s*([\w]+)\s*\?>)"
+        matches = re.findall(ifndef_regex, xml_str)
+        for group_ifndef, group_tag, group_var in matches:
+            if group_tag == "ifdef":
+                result = group_var in self.cus_vars
+            else:
+                result = group_var not in self.cus_vars
+            xml_str = xml_str.replace(group_ifndef, f"<?if {result}?>")
+        return xml_str
+
+    def _pp_if_elseif(self, xml_str: str) -> str:
+        if_elif_else_regex = (
+            r"(<\?if\s(True|False)\?>"
+            r"(.*?)"
+            r"<\?elseif\s(True|False)\?>"
+            r"(.*?)"
+            r"<\?else\?>"
+            r"(.*?)"
+            r"<\?endif\?>)"
+        )
+        if_else_regex = (
+            r"(<\?if\s(True|False)\?>"
+            r"(.*?)"
+            r"<\?else\?>"
+            r"(.*?)"
+            r"<\?endif\?>)"
+        )
+        if_regex = r"(<\?if\s(True|False)\?>(.*?)<\?endif\?>)"
+        matches = re.findall(if_elif_else_regex, xml_str, re.DOTALL)
+        for (group_full, group_if, group_if_elif, group_elif,
+             group_elif_else, group_else) in matches:
+            result = ""
+            if group_if == "True":
+                result = group_if_elif
+            elif group_elif == "True":
+                result = group_elif_else
+            else:
+                result = group_else
+            xml_str = xml_str.replace(group_full, result)
+        matches = re.findall(if_else_regex, xml_str, re.DOTALL)
+        for group_full, group_if, group_if_else, group_else in matches:
+            result = ""
+            if group_if == "True":
+                result = group_if_else
+            else:
+                result = group_else
+            xml_str = xml_str.replace(group_full, result)
+        matches = re.findall(if_regex, xml_str, re.DOTALL)
+        for group_full, group_if, group_text in matches:
+            result = ""
+            if group_if == "True":
+                result = group_text
+            xml_str = xml_str.replace(group_full, result)
+        return xml_str
+
+    def _pp_command(self, xml_str: str) -> str:
+        cmd_regex = r"(<\?cmd\s*\"([^\"]+)\"\s*\?>)"
+        matches = re.findall(cmd_regex, xml_str)
+        for group_cmd, group_exec in matches:
+            output = subprocess.check_output(
+                group_exec, shell=True,
+                text=True, stderr=subprocess.STDOUT
+            )
+            xml_str = xml_str.replace(group_cmd, output)
+        return xml_str
+
+    def _pp_blanks(self, xml_str: str) -> str:
+        right_blank_regex = r">[\n\s\t\r]*"
+        left_blank_regex = r"[\n\s\t\r]*<"
+        xml_str = re.sub(right_blank_regex, ">", xml_str)
+        xml_str = re.sub(left_blank_regex, "<", xml_str)
+        return xml_str
+
+    def preprocess(self, xml_str: str) -> str:
+        fns = [
+            self._pp_blanks,
+            self._pp_include,
+            self._pp_foreach,
+            self._pp_env_var,
+            self._pp_sys_var,
+            self._pp_cus_var,
+            self._pp_if_eval,
+            self._pp_ifdef_ifndef,
+            self._pp_if_elseif,
+            self._pp_command,
+            self._pp_error_warning,
+        ]
+
+        while True:
+            changed = False
+            for func in fns:
+                out_xml = func(xml_str)
+                if not changed and out_xml != xml_str:
+                    changed = True
+                xml_str = out_xml
+            if not changed:
+                break
+
+        return xml_str
+
+
+def preprocess_xml(path: str) -> str:
+    with open(path, "r", encoding="utf-8") as original_file:
+        input_xml = original_file.read()
+
+        proc = Preprocessor()
+        return proc.preprocess(input_xml)
+
+
+def save_xml(xml_str: str, path: Optional[str]):
+    xml = minidom.parseString(xml_str)
+    with open(path, "w", encoding="utf-8") if path else sys.stdout as output_file:
+        output_file.write(xml.toprettyxml())
+
+
+def main():
+    if len(sys.argv) < 2:
+        print("Usage: xml-preprocessor input.xml [output.xml]")
+        sys.exit(1)
+
+    output_file = None
+    if len(sys.argv) == 3:
+        output_file = sys.argv[2]
+
+    input_file = sys.argv[1]
+    output_xml = preprocess_xml(input_file)
+    save_xml(output_xml, output_file)
+
+
+if __name__ == "__main__":
+    main()
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 17/33] ui/dbus: win32 support
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (15 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 16/33] scripts: add a XML preprocessor script marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-29 17:55   ` Bernhard Beschow
  2023-06-27 13:02 ` [PULL 18/33] qtest: add qtest_pid() marcandre.lureau
                   ` (15 subsequent siblings)
  32 siblings, 1 reply; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann,
	Paolo Bonzini, Daniel P. Berrangé,
	Thomas Huth, Philippe Mathieu-Daudé

From: Marc-André Lureau <marcandre.lureau@redhat.com>

D-Bus doesn't support fd-passing on Windows (AF_UNIX doesn't have
SCM_RIGHTS yet, but there are other means to share objects. I have
proposed various solutions upstream, but none seem fitting enough atm).

To make the "-display dbus" work on Windows, implement an alternative
D-Bus interface where all the 'h' (FDs) arguments are replaced with
'ay' (WSASocketW data), and sockets are passed to the other end via
WSADuplicateSocket().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-6-marcandre.lureau@redhat.com>
---
 meson.build          |  4 +--
 ui/dbus.h            |  6 +++++
 audio/dbusaudio.c    | 44 +++++++++++++++++++++++++++------
 ui/dbus-chardev.c    | 22 +++++++++++++----
 ui/dbus-console.c    | 59 ++++++++++++++++++++++++++++++++++++++------
 ui/dbus-display1.xml | 28 +++++++++++++++++++++
 ui/meson.build       |  9 ++++++-
 7 files changed, 149 insertions(+), 23 deletions(-)

diff --git a/meson.build b/meson.build
index b409788832..9a1ce43471 100644
--- a/meson.build
+++ b/meson.build
@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
   gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support control flow integrity'
 endif
 
+xml_pp = find_program('scripts/xml-preprocess.py')
+
 lttng = not_found
 if 'ust' in get_option('trace_backends')
   lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
@@ -1985,8 +1987,6 @@ dbus_display = get_option('dbus_display') \
            error_message: '-display dbus requires glib>=2.64') \
   .require(gdbus_codegen.found(),
            error_message: gdbus_codegen_error.format('-display dbus')) \
-  .require(targetos != 'windows',
-           error_message: '-display dbus is not available on Windows') \
   .allowed()
 
 have_virtfs = get_option('virtfs') \
diff --git a/ui/dbus.h b/ui/dbus.h
index 9c149e7b41..1e8c24a48e 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -62,6 +62,12 @@ struct DBusDisplay {
     Notifier notifier;
 };
 
+#ifdef WIN32
+bool
+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
+                         GVariant *arg_listener, int *socket);
+#endif
+
 #define TYPE_DBUS_DISPLAY "dbus-display"
 OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
 
diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
index de59467d9e..7a11fbfb42 100644
--- a/audio/dbusaudio.c
+++ b/audio/dbusaudio.c
@@ -33,6 +33,7 @@
 #include <gio/gunixfdlist.h>
 #endif
 
+#include "ui/dbus.h"
 #include "ui/dbus-display1.h"
 
 #define AUDIO_CAP "dbus"
@@ -422,7 +423,6 @@ dbus_audio_fini(void *opaque)
     g_free(da);
 }
 
-#ifdef G_OS_UNIX
 static void
 listener_out_vanished_cb(GDBusConnection *connection,
                          gboolean remote_peer_vanished,
@@ -448,7 +448,9 @@ listener_in_vanished_cb(GDBusConnection *connection,
 static gboolean
 dbus_audio_register_listener(AudioState *s,
                              GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
                              GUnixFDList *fd_list,
+#endif
                              GVariant *arg_listener,
                              bool out)
 {
@@ -475,6 +477,11 @@ dbus_audio_register_listener(AudioState *s,
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
 
+#ifdef G_OS_WIN32
+    if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
+        return DBUS_METHOD_INVOCATION_HANDLED;
+    }
+#else
     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
     if (err) {
         g_dbus_method_invocation_return_error(invocation,
@@ -484,6 +491,7 @@ dbus_audio_register_listener(AudioState *s,
                                               err->message);
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
+#endif
 
     socket = g_socket_new_from_fd(fd, &err);
     if (err) {
@@ -492,15 +500,28 @@ dbus_audio_register_listener(AudioState *s,
                                               DBUS_DISPLAY_ERROR_FAILED,
                                               "Couldn't make a socket: %s",
                                               err->message);
+#ifdef G_OS_WIN32
+        closesocket(fd);
+#else
+        close(fd);
+#endif
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
     socket_conn = g_socket_connection_factory_create_connection(socket);
     if (out) {
         qemu_dbus_display1_audio_complete_register_out_listener(
-            da->iface, invocation, NULL);
+            da->iface, invocation
+#ifdef G_OS_UNIX
+            , NULL
+#endif
+            );
     } else {
         qemu_dbus_display1_audio_complete_register_in_listener(
-            da->iface, invocation, NULL);
+            da->iface, invocation
+#ifdef G_OS_UNIX
+            , NULL
+#endif
+            );
     }
 
     listener_conn =
@@ -578,24 +599,33 @@ dbus_audio_register_listener(AudioState *s,
 static gboolean
 dbus_audio_register_out_listener(AudioState *s,
                                  GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
                                  GUnixFDList *fd_list,
+#endif
                                  GVariant *arg_listener)
 {
     return dbus_audio_register_listener(s, invocation,
-                                        fd_list, arg_listener, true);
+#ifdef G_OS_UNIX
+                                        fd_list,
+#endif
+                                        arg_listener, true);
 
 }
 
 static gboolean
 dbus_audio_register_in_listener(AudioState *s,
                                 GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
                                 GUnixFDList *fd_list,
+#endif
                                 GVariant *arg_listener)
 {
     return dbus_audio_register_listener(s, invocation,
-                                        fd_list, arg_listener, false);
-}
+#ifdef G_OS_UNIX
+                                        fd_list,
 #endif
+                                        arg_listener, false);
+}
 
 static void
 dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
@@ -610,14 +640,12 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
 
     da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
     da->iface = qemu_dbus_display1_audio_skeleton_new();
-#ifdef G_OS_UNIX
     g_object_connect(da->iface,
                      "swapped-signal::handle-register-in-listener",
                      dbus_audio_register_in_listener, s,
                      "swapped-signal::handle-register-out-listener",
                      dbus_audio_register_out_listener, s,
                      NULL);
-#endif
 
     g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
                                          G_DBUS_INTERFACE_SKELETON(da->iface));
diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c
index 7154d81a9a..1d3a7122a1 100644
--- a/ui/dbus-chardev.c
+++ b/ui/dbus-chardev.c
@@ -110,18 +110,24 @@ dbus_chardev_init(DBusDisplay *dpy)
                          dbus_display_chardev_foreach, dpy);
 }
 
-#ifdef G_OS_UNIX
 static gboolean
 dbus_chr_register(
     DBusChardev *dc,
     GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
     GUnixFDList *fd_list,
+#endif
     GVariant *arg_stream,
     QemuDBusDisplay1Chardev *object)
 {
     g_autoptr(GError) err = NULL;
     int fd;
 
+#ifdef G_OS_WIN32
+    if (!dbus_win32_import_socket(invocation, arg_stream, &fd)) {
+        return DBUS_METHOD_INVOCATION_HANDLED;
+    }
+#else
     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_stream), &err);
     if (err) {
         g_dbus_method_invocation_return_error(
@@ -131,13 +137,18 @@ dbus_chr_register(
             "Couldn't get peer FD: %s", err->message);
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
+#endif
 
     if (qemu_chr_add_client(CHARDEV(dc), fd) < 0) {
         g_dbus_method_invocation_return_error(invocation,
                                               DBUS_DISPLAY_ERROR,
                                               DBUS_DISPLAY_ERROR_FAILED,
                                               "Couldn't register FD!");
+#ifdef G_OS_WIN32
+        closesocket(fd);
+#else
         close(fd);
+#endif
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
 
@@ -145,10 +156,13 @@ dbus_chr_register(
                  "owner", g_dbus_method_invocation_get_sender(invocation),
                  NULL);
 
-    qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
+    qemu_dbus_display1_chardev_complete_register(object, invocation
+#ifndef G_OS_WIN32
+                                                 , NULL
+#endif
+        );
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
-#endif
 
 static gboolean
 dbus_chr_send_break(
@@ -179,10 +193,8 @@ dbus_chr_open(Chardev *chr, ChardevBackend *backend,
     dc->iface = qemu_dbus_display1_chardev_skeleton_new();
     g_object_set(dc->iface, "name", backend->u.dbus.data->name, NULL);
     g_object_connect(dc->iface,
-#ifdef G_OS_UNIX
                      "swapped-signal::handle-register",
                      dbus_chr_register, dc,
-#endif
                      "swapped-signal::handle-send-break",
                      dbus_chr_send_break, dc,
                      NULL);
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index d5f6c93637..4a1c1fb55e 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -165,7 +165,6 @@ dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
     gobject_class->dispose = dbus_display_console_dispose;
 }
 
-#ifdef G_OS_UNIX
 static void
 listener_vanished_cb(DBusDisplayListener *listener)
 {
@@ -177,7 +176,6 @@ listener_vanished_cb(DBusDisplayListener *listener)
     g_hash_table_remove(ddc->listeners, name);
     qkbd_state_lift_all_keys(ddc->kbd);
 }
-#endif
 
 static gboolean
 dbus_console_set_ui_info(DBusDisplayConsole *ddc,
@@ -211,11 +209,47 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
 
-#ifdef G_OS_UNIX
+#ifdef G_OS_WIN32
+bool
+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
+                         GVariant *arg_listener, int *socket)
+{
+    gsize n;
+    WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
+
+    if (!info || n != sizeof(*info)) {
+        g_dbus_method_invocation_return_error(
+            invocation,
+            DBUS_DISPLAY_ERROR,
+            DBUS_DISPLAY_ERROR_FAILED,
+            "Failed to get socket infos");
+        return false;
+    }
+
+    *socket = WSASocketW(FROM_PROTOCOL_INFO,
+                         FROM_PROTOCOL_INFO,
+                         FROM_PROTOCOL_INFO,
+                         info, 0, 0);
+    if (*socket == INVALID_SOCKET) {
+        g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
+        g_dbus_method_invocation_return_error(
+            invocation,
+            DBUS_DISPLAY_ERROR,
+            DBUS_DISPLAY_ERROR_FAILED,
+            "Couldn't create socket: %s", emsg);
+        return false;
+    }
+
+    return true;
+}
+#endif
+
 static gboolean
 dbus_console_register_listener(DBusDisplayConsole *ddc,
                                GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
                                GUnixFDList *fd_list,
+#endif
                                GVariant *arg_listener)
 {
     const char *sender = g_dbus_method_invocation_get_sender(invocation);
@@ -237,6 +271,11 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
 
+#ifdef G_OS_WIN32
+    if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
+        return DBUS_METHOD_INVOCATION_HANDLED;
+    }
+#else
     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
     if (err) {
         g_dbus_method_invocation_return_error(
@@ -246,6 +285,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
             "Couldn't get peer fd: %s", err->message);
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
+#endif
 
     socket = g_socket_new_from_fd(fd, &err);
     if (err) {
@@ -254,13 +294,21 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
             DBUS_DISPLAY_ERROR,
             DBUS_DISPLAY_ERROR_FAILED,
             "Couldn't make a socket: %s", err->message);
+#ifdef G_OS_WIN32
+        closesocket(fd);
+#else
         close(fd);
+#endif
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
     socket_conn = g_socket_connection_factory_create_connection(socket);
 
     qemu_dbus_display1_console_complete_register_listener(
-        ddc->iface, invocation, NULL);
+        ddc->iface, invocation
+#ifdef G_OS_UNIX
+        , NULL
+#endif
+    );
 
     listener_conn = g_dbus_connection_new_sync(
         G_IO_STREAM(socket_conn),
@@ -287,7 +335,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
     trace_dbus_registered_listener(sender);
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
-#endif
 
 static gboolean
 dbus_kbd_press(DBusDisplayConsole *ddc,
@@ -516,10 +563,8 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
         "device-address", device_addr,
         NULL);
     g_object_connect(ddc->iface,
-#ifdef G_OS_UNIX
         "swapped-signal::handle-register-listener",
         dbus_console_register_listener, ddc,
-#endif
         "swapped-signal::handle-set-uiinfo",
         dbus_console_set_ui_info, ddc,
         NULL);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index cc0c9b68bf..cd596f774e 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -57,7 +57,13 @@
         :dbus:iface:`org.qemu.Display1.Listener` interface.
     -->
     <method name="RegisterListener">
+      <?if $(env.TARGETOS) == windows?>
+      <arg type="ay" name="listener" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+      <?else?>
       <arg type="h" name="listener" direction="in"/>
+      <?endif?>
     </method>
 
     <!--
@@ -334,6 +340,9 @@
       </arg>
     </method>
 
+    <?if $(env.TARGETOS) == windows?>
+    <!-- Add shared memory/texture support -->
+    <?else?>
     <!--
         ScanoutDMABUF:
         @dmabuf: the DMABUF file descriptor.
@@ -372,6 +381,7 @@
       <arg type="i" name="width" direction="in"/>
       <arg type="i" name="height" direction="in"/>
     </method>
+    <?endif?>
 
     <!--
         Disable:
@@ -532,7 +542,13 @@
         :dbus:iface:`org.qemu.Display1.AudioOutListener` interface.
     -->
     <method name="RegisterOutListener">
+      <?if $(env.TARGETOS) == windows?>
+      <arg type="ay" name="listener" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+      <?else?>
       <arg type="h" name="listener" direction="in"/>
+      <?endif?>
     </method>
 
     <!--
@@ -547,7 +563,13 @@
         :dbus:iface:`org.qemu.Display1.AudioInListener` interface.
     -->
     <method name="RegisterInListener">
+      <?if $(env.TARGETOS) == windows?>
+      <arg type="ay" name="listener" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+      <?else?>
       <arg type="h" name="listener" direction="in"/>
+      <?endif?>
     </method>
   </interface>
 
@@ -760,7 +782,13 @@
         The current handler, if any, will be replaced.
     -->
     <method name="Register">
+      <?if $(env.TARGETOS) == windows?>
+      <arg type="ay" name="listener" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+      <?else?>
       <arg type="h" name="stream" direction="in"/>
+      <?endif?>
     </method>
 
     <!--
diff --git a/ui/meson.build b/ui/meson.build
index a5506ac8ad..d84650676d 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -74,9 +74,16 @@ endif
 
 if dbus_display
   dbus_ss = ss.source_set()
+  env = environment()
+  env.set('TARGETOS', targetos)
+  xml = custom_target('dbus-display preprocess',
+                      input: 'dbus-display1.xml',
+                      output: 'dbus-display1.xml',
+                      env: env,
+                      command: [xml_pp, '@INPUT@', '@OUTPUT@'])
   dbus_display1 = custom_target('dbus-display gdbus-codegen',
                                 output: ['dbus-display1.h', 'dbus-display1.c'],
-                                input: files('dbus-display1.xml'),
+                                input: xml,
                                 command: [gdbus_codegen, '@INPUT@',
                                           '--glib-min-required', '2.64',
                                           '--output-directory', meson.current_build_dir(),
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 18/33] qtest: add qtest_pid()
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (16 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 17/33] ui/dbus: win32 support marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 19/33] tests: make dbus-display-test work on win32 marcandre.lureau
                   ` (14 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Thomas Huth,
	Laurent Vivier, Paolo Bonzini

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Used in the following test on win32, to share sockets with the QEMU
process.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20230606115658.677673-7-marcandre.lureau@redhat.com>
---
 tests/qtest/libqtest.h | 9 +++++++++
 tests/qtest/libqtest.c | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index a12acf7fa9..913acc3d5c 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -985,4 +985,13 @@ void qtest_qom_set_bool(QTestState *s, const char *path, const char *property,
  * Returns: Value retrieved from property.
  */
 bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property);
+
+/**
+ * qtest_pid:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: the PID of the QEMU process, or <= 0
+ */
+pid_t qtest_pid(QTestState *s);
+
 #endif
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index de03ef5f60..79152f0ec3 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -142,6 +142,11 @@ static int socket_accept(int sock)
     return ret;
 }
 
+pid_t qtest_pid(QTestState *s)
+{
+    return s->qemu_pid;
+}
+
 bool qtest_probe_child(QTestState *s)
 {
     pid_t pid = s->qemu_pid;
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 19/33] tests: make dbus-display-test work on win32
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (17 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 18/33] qtest: add qtest_pid() marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 20/33] ui/dbus: introduce "Interfaces" properties marcandre.lureau
                   ` (13 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Thomas Huth,
	Laurent Vivier, Paolo Bonzini

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20230606115658.677673-8-marcandre.lureau@redhat.com>
---
 tests/qtest/dbus-display-test.c | 43 ++++++++++++++++++++++++++++++---
 tests/qtest/meson.build         |  2 +-
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c
index fef025ac6f..21edaa1e32 100644
--- a/tests/qtest/dbus-display-test.c
+++ b/tests/qtest/dbus-display-test.c
@@ -1,4 +1,5 @@
 #include "qemu/osdep.h"
+#include "qemu/sockets.h"
 #include "qemu/dbus.h"
 #include "qemu/sockets.h"
 #include <gio/gio.h>
@@ -14,7 +15,11 @@ test_dbus_p2p_from_fd(int fd)
     g_autoptr(GSocketConnection) socketc = NULL;
     GDBusConnection *conn;
 
+#ifdef WIN32
+    socket = g_socket_new_from_fd(_get_osfhandle(fd), &err);
+#else
     socket = g_socket_new_from_fd(fd, &err);
+#endif
     g_assert_no_error(err);
 
     socketc = g_socket_connection_factory_create_connection(socket);
@@ -126,7 +131,10 @@ test_dbus_console_registered(GObject *source_object,
 
     qemu_dbus_display1_console_call_register_listener_finish(
         QEMU_DBUS_DISPLAY1_CONSOLE(source_object),
-        NULL, res, &err);
+#ifndef WIN32
+        NULL,
+#endif
+        res, &err);
     g_assert_no_error(err);
 
     test->listener_conn = g_thread_join(test->thread);
@@ -145,17 +153,25 @@ test_dbus_display_console(void)
     g_autoptr(GError) err = NULL;
     g_autoptr(GDBusConnection) conn = NULL;
     g_autoptr(QemuDBusDisplay1ConsoleProxy) console = NULL;
-    g_autoptr(GUnixFDList) fd_list = NULL;
     g_autoptr(GMainLoop) loop = NULL;
     QTestState *qts = NULL;
-    int pair[2], idx;
+    int pair[2];
     TestDBusConsoleRegister test;
+#ifdef WIN32
+    WSAPROTOCOL_INFOW info;
+    g_autoptr(GVariant) listener = NULL;
+#else
+    g_autoptr(GUnixFDList) fd_list = NULL;
+    int idx;
+#endif
 
     test_setup(&qts, &conn);
 
     g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
+#ifndef WIN32
     fd_list = g_unix_fd_list_new();
     idx = g_unix_fd_list_append(fd_list, pair[1], NULL);
+#endif
 
     console = QEMU_DBUS_DISPLAY1_CONSOLE_PROXY(
         qemu_dbus_display1_console_proxy_new_sync(
@@ -171,12 +187,33 @@ test_dbus_display_console(void)
     test.thread = g_thread_new(NULL, test_dbus_p2p_server_setup_thread,
                                GINT_TO_POINTER(pair[0]));
 
+#ifdef WIN32
+    if (WSADuplicateSocketW(_get_osfhandle(pair[1]),
+                            GetProcessId((HANDLE) qtest_pid(qts)),
+                            &info) == SOCKET_ERROR)
+    {
+        g_autofree char *emsg = g_win32_error_message(WSAGetLastError());
+        g_error("WSADuplicateSocket failed: %s", emsg);
+    }
+    close(pair[1]);
+    listener = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+                                         &info,
+                                         sizeof(info),
+                                         1);
+#endif
+
     qemu_dbus_display1_console_call_register_listener(
         QEMU_DBUS_DISPLAY1_CONSOLE(console),
+#ifdef WIN32
+        listener,
+#else
         g_variant_new_handle(idx),
+#endif
         G_DBUS_CALL_FLAGS_NONE,
         -1,
+#ifndef WIN32
         fd_list,
+#endif
         NULL,
         test_dbus_console_registered,
         &test);
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 5fa6833ad7..74630f6672 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -104,7 +104,7 @@ qtests_i386 = \
    'numa-test'
   ]
 
-if dbus_display and targetos != 'windows'
+if dbus_display
   qtests_i386 += ['dbus-display-test']
 endif
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 20/33] ui/dbus: introduce "Interfaces" properties
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (18 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 19/33] tests: make dbus-display-test work on win32 marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 21/33] console/win32: allocate shareable display surface marcandre.lureau
                   ` (12 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

This property is similar to ``org.freedesktop.DBus.Interfaces`` property
on the bus interface: it's an array of strings listing the extra
interfaces and capabilities available, in a convenient way.

Most interfaces are implicit, as they are required. For
``org/qemu/Display1_$id``, we can list the Keyboard And Mouse
interfaces. Those could be optional.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-9-marcandre.lureau@redhat.com>
---
 ui/dbus-console.c    |   7 +++
 ui/dbus-display1.xml | 118 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 4a1c1fb55e..aaa9d3b0b3 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -537,6 +537,12 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
     char device_addr[256] = "";
     DBusDisplayConsole *ddc;
     int idx, i;
+    const char *interfaces[] = {
+        "org.qemu.Display1.Keyboard",
+        "org.qemu.Display1.Mouse",
+        "org.qemu.Display1.MultiTouch",
+        NULL
+    };
 
     assert(display);
     assert(con);
@@ -561,6 +567,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
         "width", qemu_console_get_width(con, 0),
         "height", qemu_console_get_height(con, 0),
         "device-address", device_addr,
+        "interfaces", interfaces,
         NULL);
     g_object_connect(ddc->iface,
         "swapped-signal::handle-register-listener",
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index cd596f774e..06e8779c04 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -26,6 +26,20 @@
         The list of consoles available on ``/org/qemu/Display1/Console_$id``.
     -->
     <property name="ConsoleIDs" type="au" access="read"/>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        /org/qemu/Display1/VM object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
@@ -127,12 +141,27 @@
         The device address (ex: "pci/0000/02.0").
     -->
     <property name="DeviceAddress" type="s" access="read"/>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        ``/org/qemu/Display1/Console_$id`` object, and can be used to detect the
+        capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
       org.qemu.Display1.Keyboard:
 
-      This interface in implemented on ``/org/qemu/Display1/Console_$id`` (see
+      This interface is optionally implemented on
+      ``/org/qemu/Display1/Console_$id`` (see
       :dbus:iface:`~org.qemu.Display1.Console`).
   -->
   <interface name="org.qemu.Display1.Keyboard">
@@ -171,7 +200,8 @@
   <!--
       org.qemu.Display1.Mouse:
 
-      This interface in implemented on ``/org/qemu/Display1/Console_$id`` (see
+      This interface is optionally implemented on
+      ``/org/qemu/Display1/Console_$id`` (see
       :dbus:iface:`~org.qemu.Display1.Console` documentation).
 
       .. _dbus-button-values:
@@ -425,6 +455,20 @@
         <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
       </arg>
     </method>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        /org/qemu/Display1/Listener object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
@@ -522,6 +566,20 @@
         <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
       </arg>
     </method>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        /org/qemu/Display1/Clipboard object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
@@ -571,6 +629,20 @@
       <arg type="h" name="listener" direction="in"/>
       <?endif?>
     </method>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        /org/qemu/Display1/Audio object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
@@ -657,6 +729,20 @@
         <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
       </arg>
     </method>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        /org/qemu/Display1/AudioOutListener object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
@@ -745,6 +831,20 @@
         <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
       </arg>
     </method>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        /org/qemu/Display1/AudioInListener object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 
   <!--
@@ -826,5 +926,19 @@
         The D-Bus unique name of the registered handler.
     -->
     <property name="Owner" type="s" access="read"/>
+
+    <!--
+        Interfaces:
+
+        This property lists extra interfaces provided by the
+        ``/org/qemu/Display1/Chardev_$i`` object, and can be used to detect
+        the capabilities with which they are communicating.
+
+        Unlike the standard D-Bus Introspectable interface, querying this
+        property does not require parsing XML.
+
+        (earlier version of the display interface do not provide this property)
+    -->
+    <property name="Interfaces" type="as" access="read"/>
   </interface>
 </node>
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 21/33] console/win32: allocate shareable display surface
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (19 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 20/33] ui/dbus: introduce "Interfaces" properties marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images marcandre.lureau
                   ` (11 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Stefan Weil, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Introduce qemu_win32_map_alloc() and qemu_win32_map_free() to allocate
shared memory mapping. The handle can be used to share the mapping with
another process.

Teach qemu_create_displaysurface() to allocate shared memory. Following
patches will introduce other places for shared memory allocation.

Other patches for -display dbus will share the memory when possible with
the client, to avoid expensive memory copy between the processes.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-10-marcandre.lureau@redhat.com>
---
 include/sysemu/os-win32.h |  3 ++
 include/ui/console.h      |  8 ++++++
 ui/console.c              | 59 ++++++++++++++++++++++++++++++++++-----
 ui/qemu-pixman.c          |  1 +
 util/oslib-win32.c        | 33 ++++++++++++++++++++++
 ui/trace-events           |  2 +-
 util/trace-events         |  4 +++
 7 files changed, 102 insertions(+), 8 deletions(-)

diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 65f6c9ea57..91aa0d7ec0 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -263,6 +263,9 @@ EXCEPTION_DISPOSITION
 win32_close_exception_handler(struct _EXCEPTION_RECORD*, void*,
                               struct _CONTEXT*, void*);
 
+void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp);
+void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/ui/console.h b/include/ui/console.h
index 2093e2a3ba..2ab0c7112a 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -143,6 +143,10 @@ typedef struct DisplaySurface {
     GLenum gltype;
     GLuint texture;
 #endif
+#ifdef WIN32
+    HANDLE handle;
+    uint32_t handle_offset;
+#endif
 } DisplaySurface;
 
 typedef struct QemuUIInfo {
@@ -329,6 +333,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
 DisplaySurface *qemu_create_placeholder_surface(int w, int h,
                                                 const char *msg);
+#ifdef WIN32
+void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
+                                          HANDLE h, uint32_t offset);
+#endif
 PixelFormat qemu_default_pixelformat(int bpp);
 
 DisplaySurface *qemu_create_displaysurface(int width, int height);
diff --git a/ui/console.c b/ui/console.c
index cfaa43e970..4957110723 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1513,18 +1513,59 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
     return s;
 }
 
+#ifdef WIN32
+void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
+                                          HANDLE h, uint32_t offset)
+{
+    assert(!surface->handle);
+
+    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 *surface = g_new0(DisplaySurface, 1);
+    DisplaySurface *surface;
+    void *bits = NULL;
+#ifdef WIN32
+    HANDLE handle = NULL;
+#endif
 
-    trace_displaysurface_create(surface, width, height);
-    surface->format = PIXMAN_x8r8g8b8;
-    surface->image = pixman_image_create_bits(surface->format,
-                                              width, height,
-                                              NULL, width * 4);
-    assert(surface->image != NULL);
+    trace_displaysurface_create(width, height);
+
+#ifdef WIN32
+    bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
+#endif
+
+    surface = qemu_create_displaysurface_from(
+        width, height,
+        PIXMAN_x8r8g8b8,
+        width * 4, bits
+    );
     surface->flags = QEMU_ALLOCATED_FLAG;
 
+#ifdef WIN32
+    qemu_displaysurface_win32_set_handle(surface, handle, 0);
+#endif
     return surface;
 }
 
@@ -1540,6 +1581,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
                                               width, height,
                                               (void *)data, linesize);
     assert(surface->image != NULL);
+#ifdef WIN32
+    pixman_image_set_destroy_function(surface->image,
+                                      win32_pixman_image_destroy, surface);
+#endif
 
     return surface;
 }
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 3ab7e2e958..e4f024a85e 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -6,6 +6,7 @@
 #include "qemu/osdep.h"
 #include "ui/console.h"
 #include "standard-headers/drm/drm_fourcc.h"
+#include "trace.h"
 
 PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
 {
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index fafbab80b4..429542face 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -835,3 +835,36 @@ int qemu_msync(void *addr, size_t length, int fd)
      */
     return qemu_fdatasync(fd);
 }
+
+void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp)
+{
+    void *bits;
+
+    trace_win32_map_alloc(size);
+
+    *h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+                          size, NULL);
+    if (*h == NULL) {
+        error_setg_win32(errp, GetLastError(), "Failed to CreateFileMapping");
+        return NULL;
+    }
+
+    bits = MapViewOfFile(*h, FILE_MAP_ALL_ACCESS, 0, 0, size);
+    if (bits == NULL) {
+        error_setg_win32(errp, GetLastError(), "Failed to MapViewOfFile");
+        CloseHandle(*h);
+        return NULL;
+    }
+
+    return bits;
+}
+
+void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp)
+{
+    trace_win32_map_free(ptr, h);
+
+    if (UnmapViewOfFile(ptr) == 0) {
+        error_setg_win32(errp, GetLastError(), "Failed to UnmapViewOfFile");
+    }
+    CloseHandle(h);
+}
diff --git a/ui/trace-events b/ui/trace-events
index 138a09cc03..a71895c479 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -9,7 +9,7 @@ console_putchar_unhandled(int ch) "unhandled escape character '%c'"
 console_txt_new(int w, int h) "%dx%d"
 console_select(int nr) "%d"
 console_refresh(int interval) "interval %d ms"
-displaysurface_create(void *display_surface, int w, int h) "surface=%p, %dx%d"
+displaysurface_create(int w, int h) "%dx%d"
 displaysurface_create_from(void *display_surface, int w, int h, uint32_t format) "surface=%p, %dx%d, format 0x%x"
 displaysurface_create_pixman(void *display_surface) "surface=%p"
 displaysurface_free(void *display_surface) "surface=%p"
diff --git a/util/trace-events b/util/trace-events
index 3f7e766683..49a4962e18 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -52,6 +52,10 @@ qemu_anon_ram_alloc(size_t size, void *ptr) "size %zu ptr %p"
 qemu_vfree(void *ptr) "ptr %p"
 qemu_anon_ram_free(void *ptr, size_t size) "ptr %p size %zu"
 
+# oslib-win32.c
+win32_map_alloc(size_t size) "size:%zd"
+win32_map_free(void *ptr, void *h) "ptr:%p handle:%p"
+
 # hbitmap.c
 hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
 hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (20 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 21/33] console/win32: allocate shareable display surface marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-07-03 11:45   ` Alexander Bulekov
  2023-07-03 14:11   ` Peter Maydell
  2023-06-27 13:02 ` [PULL 23/33] ui/dbus: use shared memory when possible on win32 marcandre.lureau
                   ` (10 subsequent siblings)
  32 siblings, 2 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Michael S. Tsirkin,
	Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Allocate pixman bits for scanouts with qemu_win32_map_alloc() so we can
set a shareable handle on the associated display surface.

Note: when bits are provided to pixman_image_create_bits(), you must also give
the rowstride (the argument is ignored when bits is NULL)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-11-marcandre.lureau@redhat.com>
---
 include/hw/virtio/virtio-gpu.h |  3 +++
 hw/display/virtio-gpu.c        | 46 +++++++++++++++++++++++++++++++---
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 2e28507efe..7a5f8056ea 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -48,6 +48,9 @@ struct virtio_gpu_simple_resource {
     unsigned int iov_cnt;
     uint32_t scanout_bitmask;
     pixman_image_t *image;
+#ifdef WIN32
+    HANDLE handle;
+#endif
     uint64_t hostmem;
 
     uint64_t blob_size;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 1f8a5b16c6..347e17d490 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -258,6 +258,16 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
     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,
                                           struct virtio_gpu_ctrl_command *cmd)
 {
@@ -304,12 +314,27 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
 
     res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
     if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
+        void *bits = NULL;
+#ifdef WIN32
+        bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
+        if (!bits) {
+            goto end;
+        }
+#endif
         res->image = pixman_image_create_bits(pformat,
                                               c2d.width,
                                               c2d.height,
-                                              NULL, 0);
+                                              bits, res->hostmem / c2d.height);
+#ifdef WIN32
+        if (res->image) {
+            pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
+        }
+#endif
     }
 
+#ifdef WIN32
+end:
+#endif
     if (!res->image) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: resource creation failed %d %d %d\n",
@@ -685,6 +710,9 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
             *error = VIRTIO_GPU_RESP_ERR_UNSPEC;
             return;
         }
+#ifdef WIN32
+        qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
+#endif
 
         pixman_image_unref(rect);
         dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
@@ -1228,6 +1256,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
     struct virtio_gpu_simple_resource *res;
     struct virtio_gpu_scanout *scanout;
     uint32_t resource_id, pformat;
+    void *bits = NULL;
     int i;
 
     g->hostmem = 0;
@@ -1252,15 +1281,23 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
             g_free(res);
             return -EINVAL;
         }
+
+        res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
+#ifdef WIN32
+        bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
+        if (!bits) {
+            g_free(res);
+            return -EINVAL;
+        }
+#endif
         res->image = pixman_image_create_bits(pformat,
                                               res->width, res->height,
-                                              NULL, 0);
+                                              bits, res->hostmem / res->height);
         if (!res->image) {
             g_free(res);
             return -EINVAL;
         }
 
-        res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
 
         res->addrs = g_new(uint64_t, res->iov_cnt);
         res->iov = g_new(struct iovec, res->iov_cnt);
@@ -1321,6 +1358,9 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
         if (!scanout->ds) {
             return -EINVAL;
         }
+#ifdef WIN32
+        qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
+#endif
 
         dpy_gfx_replace_surface(scanout->con, scanout->ds);
         dpy_gfx_update_full(scanout->con);
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 23/33] ui/dbus: use shared memory when possible on win32
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (21 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 24/33] ui: add egl-headless support " marcandre.lureau
                   ` (9 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

When the display surface has an associated HANDLE, we can duplicate it
to the client process and let it map the memory to avoid expensive copies.

Introduce two new win32-specific methods ScanoutMap and UpdateMap. The
first is used to inform the listener about the a shared map
availability, and the second for display updates.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-12-marcandre.lureau@redhat.com>
---
 ui/dbus-listener.c   | 165 ++++++++++++++++++++++++++++++++++++++++++-
 ui/dbus-display1.xml |  48 ++++++++++++-
 2 files changed, 208 insertions(+), 5 deletions(-)

diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 41597a0078..f6b1cd11be 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -48,6 +48,14 @@ struct _DBusDisplayListener {
     DisplayChangeListener dcl;
     DisplaySurface *ds;
     int gl_updates;
+
+    bool ds_mapped;
+    bool can_share_map;
+
+#ifdef WIN32
+    QemuDBusDisplay1ListenerWin32Map *map_proxy;
+    HANDLE peer_process;
+#endif
 };
 
 G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
@@ -119,7 +127,61 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
         fd_list,
         NULL, NULL, NULL);
 }
+#endif /* OPENGL & GBM */
+
+#ifdef WIN32
+static bool dbus_scanout_map(DBusDisplayListener *ddl)
+{
+    g_autoptr(GError) err = NULL;
+    BOOL success;
+    HANDLE target_handle;
+
+    if (ddl->ds_mapped) {
+        return true;
+    }
+
+    if (!ddl->can_share_map || !ddl->ds->handle) {
+        return false;
+    }
+
+    success = DuplicateHandle(
+        GetCurrentProcess(),
+        ddl->ds->handle,
+        ddl->peer_process,
+        &target_handle,
+        FILE_MAP_READ | SECTION_QUERY,
+        FALSE, 0);
+    if (!success) {
+        g_autofree char *msg = g_win32_error_message(GetLastError());
+        g_debug("Failed to DuplicateHandle: %s", msg);
+        ddl->can_share_map = false;
+        return false;
+    }
+
+    if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
+            ddl->map_proxy,
+            GPOINTER_TO_UINT(target_handle),
+            ddl->ds->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,
+            NULL,
+            &err)) {
+        g_debug("Failed to call ScanoutMap: %s", err->message);
+        ddl->can_share_map = false;
+        return false;
+    }
+
+    ddl->ds_mapped = true;
+
+    return true;
+}
+#endif
 
+#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
 static void dbus_scanout_texture(DisplayChangeListener *dcl,
                                  uint32_t tex_id,
                                  bool backing_y_0_top,
@@ -239,7 +301,7 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
         ddl->gl_updates = 0;
     }
 }
-#endif
+#endif /* OPENGL & GBM */
 
 static void dbus_refresh(DisplayChangeListener *dcl)
 {
@@ -265,10 +327,20 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
     size_t stride;
 
     assert(ddl->ds);
-    stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
 
     trace_dbus_update(x, y, w, h);
 
+#ifdef WIN32
+    if (dbus_scanout_map(ddl)) {
+        qemu_dbus_display1_listener_win32_map_call_update_map(
+            ddl->map_proxy,
+            x, y, w, h,
+            G_DBUS_CALL_FLAGS_NONE,
+            DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+        return;
+    }
+#endif
+
     if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
         v_data = g_variant_new_from_data(
             G_VARIANT_TYPE("ay"),
@@ -290,6 +362,7 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
     }
 
     /* make a copy, since gvariant only handles linear data */
+    stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
     img = pixman_image_create_bits(surface_format(ddl->ds),
                                    w, h, NULL, stride);
     pixman_image_composite(PIXMAN_OP_SRC, ddl->ds->image, NULL, img,
@@ -333,6 +406,9 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl,
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
 
     ddl->ds = new_surface;
+#ifdef WIN32
+    ddl->ds_mapped = false;
+#endif
     if (!ddl->ds) {
         /* why not call disable instead? */
         return;
@@ -414,6 +490,10 @@ dbus_display_listener_dispose(GObject *object)
     g_clear_object(&ddl->conn);
     g_clear_pointer(&ddl->bus_name, g_free);
     g_clear_object(&ddl->proxy);
+#ifdef WIN32
+    g_clear_object(&ddl->map_proxy);
+    g_clear_pointer(&ddl->peer_process, CloseHandle);
+#endif
 
     G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
 }
@@ -459,6 +539,85 @@ dbus_display_listener_get_console(DBusDisplayListener *ddl)
     return ddl->console;
 }
 
+#ifdef WIN32
+static bool
+dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
+{
+    QemuDBusDisplay1Listener *l = QEMU_DBUS_DISPLAY1_LISTENER(ddl->proxy);
+    bool implements;
+
+    implements = g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l), iface);
+    if (!implements) {
+        g_debug("Display listener does not implement: `%s`", iface);
+    }
+
+    return implements;
+}
+#endif
+
+static void
+dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
+{
+#ifdef WIN32
+    g_autoptr(GError) err = NULL;
+    GDBusConnection *conn;
+    GIOStream *stream;
+    GSocket *sock;
+    g_autoptr(GCredentials) creds = NULL;
+    DWORD *pid;
+
+    if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
+        return;
+    }
+
+    conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy));
+    stream = g_dbus_connection_get_stream(conn);
+
+    if (!G_IS_UNIX_CONNECTION(stream)) {
+        return;
+    }
+
+    sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream));
+    creds = g_socket_get_credentials(sock, &err);
+
+    if (!creds) {
+        g_debug("Failed to get peer credentials: %s", err->message);
+        return;
+    }
+
+    pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID);
+
+    if (pid == NULL) {
+        g_debug("Failed to get peer PID");
+        return;
+    }
+
+    ddl->peer_process = OpenProcess(
+        PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
+        false, *pid);
+
+    if (!ddl->peer_process) {
+        g_autofree char *msg = g_win32_error_message(GetLastError());
+        g_debug("Failed to OpenProcess: %s", msg);
+        return;
+    }
+
+    ddl->map_proxy =
+        qemu_dbus_display1_listener_win32_map_proxy_new_sync(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 win32 map proxy: %s", err->message);
+        return;
+    }
+
+    ddl->can_share_map = true;
+#endif
+}
+
 DBusDisplayListener *
 dbus_display_listener_new(const char *bus_name,
                           GDBusConnection *conn,
@@ -487,6 +646,8 @@ dbus_display_listener_new(const char *bus_name,
     ddl->conn = conn;
     ddl->console = console;
 
+    dbus_display_listener_setup_shared_map(ddl);
+
     con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
     assert(con);
     ddl->dcl.con = con;
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index 06e8779c04..7233286b28 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -370,9 +370,7 @@
       </arg>
     </method>
 
-    <?if $(env.TARGETOS) == windows?>
-    <!-- Add shared memory/texture support -->
-    <?else?>
+    <?if $(env.TARGETOS) != windows?>
     <!--
         ScanoutDMABUF:
         @dmabuf: the DMABUF file descriptor.
@@ -471,6 +469,50 @@
     <property name="Interfaces" type="as" access="read"/>
   </interface>
 
+  <!--
+      org.qemu.Display1.Listener.Win32.Map:
+
+      This client-side interface can complement org.qemu.Display1.Listener on
+      ``/org/qemu/Display1/Listener`` for Windows specific methods.
+  -->
+  <interface name="org.qemu.Display1.Listener.Win32.Map">
+    <!--
+        ScanoutMap:
+        @handle: the shared map handle value.
+        @offset: mapping offset.
+        @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="t" 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>
+
   <!--
       org.qemu.Display1.Clipboard:
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 24/33] ui: add egl-headless support on win32
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (22 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 23/33] ui/dbus: use shared memory when possible on win32 marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 25/33] ui/egl: default to GLES on windows marcandre.lureau
                   ` (8 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann,
	Eric Blake, Markus Armbruster

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Make GBM optional for EGL code, and enable the build for win32.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-13-marcandre.lureau@redhat.com>
---
 qapi/ui.json             |  5 ++---
 include/ui/egl-helpers.h |  7 ++++++-
 ui/egl-headless.c        | 20 +++++++++++++-------
 ui/egl-helpers.c         | 38 +++++++++++++++++++++++++++++++-------
 ui/meson.build           |  6 +++---
 5 files changed, 55 insertions(+), 21 deletions(-)

diff --git a/qapi/ui.json b/qapi/ui.json
index 2755395483..bb06fb6039 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1484,8 +1484,7 @@
     { 'name': 'none' },
     { 'name': 'gtk', 'if': 'CONFIG_GTK' },
     { 'name': 'sdl', 'if': 'CONFIG_SDL' },
-    { 'name': 'egl-headless',
-              'if': { 'all': ['CONFIG_OPENGL', 'CONFIG_GBM'] } },
+    { 'name': 'egl-headless', 'if': 'CONFIG_OPENGL' },
     { 'name': 'curses', 'if': 'CONFIG_CURSES' },
     { 'name': 'cocoa', 'if': 'CONFIG_COCOA' },
     { 'name': 'spice-app', 'if': 'CONFIG_SPICE' },
@@ -1525,7 +1524,7 @@
       'cocoa': { 'type': 'DisplayCocoa', 'if': 'CONFIG_COCOA' },
       'curses': { 'type': 'DisplayCurses', 'if': 'CONFIG_CURSES' },
       'egl-headless': { 'type': 'DisplayEGLHeadless',
-                        'if': { 'all': ['CONFIG_OPENGL', 'CONFIG_GBM'] } },
+                        'if': 'CONFIG_OPENGL' },
       'dbus': { 'type': 'DisplayDBus', 'if': 'CONFIG_DBUS_DISPLAY' },
       'sdl': { 'type': 'DisplaySDL', 'if': 'CONFIG_SDL' }
   }
diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 2cf6633ad2..6c4eb5dd70 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -36,11 +36,12 @@ void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip);
 void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
                        int x, int y, double scale_x, double scale_y);
 
+extern EGLContext qemu_egl_rn_ctx;
+
 #ifdef CONFIG_GBM
 
 extern int qemu_egl_rn_fd;
 extern struct gbm_device *qemu_egl_rn_gbm_dev;
-extern EGLContext qemu_egl_rn_ctx;
 
 int egl_rendernode_init(const char *rendernode, DisplayGLMode mode);
 int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
@@ -62,6 +63,10 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode);
 
 #endif
 
+#ifdef WIN32
+int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode);
+#endif
+
 EGLContext qemu_egl_init_ctx(void);
 bool qemu_egl_has_dmabuf(void);
 
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index ef70e6a18e..e4177206f2 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -79,6 +79,8 @@ static void egl_scanout_texture(DisplayChangeListener *dcl,
     }
 }
 
+#ifdef CONFIG_GBM
+
 static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
                                QemuDmaBuf *dmabuf)
 {
@@ -110,6 +112,14 @@ static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
     }
 }
 
+static void egl_release_dmabuf(DisplayChangeListener *dcl,
+                               QemuDmaBuf *dmabuf)
+{
+    egl_dmabuf_release_texture(dmabuf);
+}
+
+#endif
+
 static void egl_cursor_position(DisplayChangeListener *dcl,
                                 uint32_t pos_x, uint32_t pos_y)
 {
@@ -119,12 +129,6 @@ static void egl_cursor_position(DisplayChangeListener *dcl,
     edpy->pos_y = pos_y;
 }
 
-static void egl_release_dmabuf(DisplayChangeListener *dcl,
-                               QemuDmaBuf *dmabuf)
-{
-    egl_dmabuf_release_texture(dmabuf);
-}
-
 static void egl_scanout_flush(DisplayChangeListener *dcl,
                               uint32_t x, uint32_t y,
                               uint32_t w, uint32_t h)
@@ -160,10 +164,12 @@ static const DisplayChangeListenerOps egl_ops = {
 
     .dpy_gl_scanout_disable  = egl_scanout_disable,
     .dpy_gl_scanout_texture  = egl_scanout_texture,
+#ifdef CONFIG_GBM
     .dpy_gl_scanout_dmabuf   = egl_scanout_dmabuf,
     .dpy_gl_cursor_dmabuf    = egl_cursor_dmabuf,
-    .dpy_gl_cursor_position  = egl_cursor_position,
     .dpy_gl_release_dmabuf   = egl_release_dmabuf,
+#endif
+    .dpy_gl_cursor_position  = egl_cursor_position,
     .dpy_gl_update           = egl_scanout_flush,
 };
 
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 26d43e0213..d1ef3c07dd 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -199,11 +199,12 @@ void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
 
 /* ---------------------------------------------------------------------- */
 
+EGLContext qemu_egl_rn_ctx;
+
 #ifdef CONFIG_GBM
 
 int qemu_egl_rn_fd;
 struct gbm_device *qemu_egl_rn_gbm_dev;
-EGLContext qemu_egl_rn_ctx;
 
 int egl_rendernode_init(const char *rendernode, DisplayGLMode mode)
 {
@@ -400,7 +401,7 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win)
 
 /* ---------------------------------------------------------------------- */
 
-#if defined(CONFIG_X11) || defined(CONFIG_GBM)
+#if defined(CONFIG_X11) || defined(CONFIG_GBM) || defined(WIN32)
 
 /*
  * Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed
@@ -508,6 +509,9 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
     return 0;
 }
 
+#endif
+
+#if defined(CONFIG_X11) || defined(CONFIG_GBM)
 int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode)
 {
 #ifdef EGL_KHR_platform_x11
@@ -525,7 +529,14 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode)
     return qemu_egl_init_dpy(dpy, 0, mode);
 #endif
 }
+#endif
+
 
+#ifdef WIN32
+int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode)
+{
+    return qemu_egl_init_dpy(dpy, 0, mode);
+}
 #endif
 
 bool qemu_egl_has_dmabuf(void)
@@ -577,15 +588,28 @@ bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
         return false;
     }
 
-#ifdef CONFIG_GBM
+#ifdef WIN32
+    if (qemu_egl_init_dpy_win32(EGL_DEFAULT_DISPLAY, mode) < 0) {
+        error_setg(errp, "egl: init failed");
+        return false;
+    }
+    qemu_egl_rn_ctx = qemu_egl_init_ctx();
+    if (!qemu_egl_rn_ctx) {
+        error_setg(errp, "egl: egl_init_ctx failed");
+        return false;
+    }
+#elif defined(CONFIG_GBM)
     if (egl_rendernode_init(rendernode, mode) < 0) {
         error_setg(errp, "egl: render node init failed");
         return false;
     }
+#endif
+
+    if (!qemu_egl_rn_ctx) {
+        error_setg(errp, "egl: not available on this platform");
+        return false;
+    }
+
     display_opengl = 1;
     return true;
-#else
-    error_setg(errp, "egl: not available on this platform");
-    return false;
-#endif
 }
diff --git a/ui/meson.build b/ui/meson.build
index d84650676d..d81609fb0e 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -65,10 +65,10 @@ if opengl.found()
   ui_modules += {'opengl' : opengl_ss}
 endif
 
-if opengl.found() and gbm.found()
+if opengl.found()
   egl_headless_ss = ss.source_set()
-  egl_headless_ss.add(when: [opengl, gbm, pixman],
-                      if_true: files('egl-headless.c'))
+  egl_headless_ss.add(when: [opengl, pixman],
+                      if_true: [files('egl-headless.c'), gbm])
   ui_modules += {'egl-headless' : egl_headless_ss}
 endif
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 25/33] ui/egl: default to GLES on windows
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (23 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 24/33] ui: add egl-headless support " marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 26/33] ui: add egl_fb_read_rect() marcandre.lureau
                   ` (7 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Windows GL drivers are notoriously not very good. Otoh, ANGLE provides
rock solid GLES implementation on top of direct3d. We should recommend
it and default to ES when using EGL (users can easily override this if
necessary)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-14-marcandre.lureau@redhat.com>
---
 ui/egl-helpers.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index d1ef3c07dd..c2a3ace743 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -535,6 +535,10 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode)
 #ifdef WIN32
 int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode)
 {
+    /* prefer GL ES, as that's what ANGLE supports */
+    if (mode == DISPLAYGL_MODE_ON) {
+        mode = DISPLAYGL_MODE_ES;
+    }
     return qemu_egl_init_dpy(dpy, 0, mode);
 }
 #endif
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 26/33] ui: add egl_fb_read_rect()
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (24 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 25/33] ui/egl: default to GLES on windows marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 27/33] ui/dbus: add GL support on win32 marcandre.lureau
                   ` (6 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Similar to egl_fb_read(), same limitations, but with extra arguments to
read a subset of the framebuffer. Used in following commits.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-15-marcandre.lureau@redhat.com>
---
 include/ui/egl-helpers.h |  1 +
 ui/egl-helpers.c         | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 6c4eb5dd70..6e2f0c49a6 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -31,6 +31,7 @@ void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
 void egl_fb_setup_new_tex(egl_fb *fb, int width, int height);
 void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip);
 void egl_fb_read(DisplaySurface *dst, egl_fb *src);
+void egl_fb_read_rect(DisplaySurface *dst, egl_fb *src, int x, int y, int w, int h);
 
 void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip);
 void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index c2a3ace743..f38800e920 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -169,6 +169,20 @@ void egl_fb_read(DisplaySurface *dst, egl_fb *src)
                  GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst));
 }
 
+void egl_fb_read_rect(DisplaySurface *dst, egl_fb *src, int x, int y, int w, int h)
+{
+    assert(surface_width(dst) == src->width);
+    assert(surface_height(dst) == src->height);
+    assert(surface_format(dst) == PIXMAN_x8r8g8b8);
+
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
+    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+    glPixelStorei(GL_PACK_ROW_LENGTH, surface_stride(dst) / 4);
+    glReadPixels(x, y, w, h,
+                 GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst) + x * 4);
+    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+}
+
 void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip)
 {
     glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 27/33] ui/dbus: add GL support on win32
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (25 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 26/33] ui: add egl_fb_read_rect() marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 28/33] ui/dbus: add some GL traces marcandre.lureau
                   ` (5 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Enable usage of dbus,gl= on win32. At this point, the scanout texture is
read on the DisplaySurface memory, and the client is then updated with
the "2D" API (with shared memory if possible).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-16-marcandre.lureau@redhat.com>
---
 ui/dbus-listener.c | 98 ++++++++++++++++++++++++++++++++--------------
 ui/dbus.c          |  4 --
 2 files changed, 68 insertions(+), 34 deletions(-)

diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index f6b1cd11be..e92eff66e3 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -36,6 +36,9 @@
 #endif
 #include "trace.h"
 
+static void dbus_gfx_switch(DisplayChangeListener *dcl,
+                            struct DisplaySurface *new_surface);
+
 struct _DBusDisplayListener {
     GObject parent;
 
@@ -55,12 +58,28 @@ struct _DBusDisplayListener {
 #ifdef WIN32
     QemuDBusDisplay1ListenerWin32Map *map_proxy;
     HANDLE peer_process;
+#ifdef CONFIG_OPENGL
+    egl_fb fb;
+#endif
 #endif
 };
 
 G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
 
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+static void dbus_gfx_update(DisplayChangeListener *dcl,
+                            int x, int y, int w, int h);
+
+#ifdef CONFIG_OPENGL
+static void dbus_scanout_disable(DisplayChangeListener *dcl)
+{
+    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+    ddl->ds = NULL;
+    qemu_dbus_display1_listener_call_disable(
+        ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+}
+
+#ifdef CONFIG_GBM
 static void dbus_update_gl_cb(GObject *source_object,
                            GAsyncResult *res,
                            gpointer user_data)
@@ -76,29 +95,31 @@ static void dbus_update_gl_cb(GObject *source_object,
     graphic_hw_gl_block(ddl->dcl.con, false);
     g_object_unref(ddl);
 }
+#endif
 
-static void dbus_call_update_gl(DBusDisplayListener *ddl,
+static void dbus_call_update_gl(DisplayChangeListener *dcl,
                                 int x, int y, int w, int h)
 {
-    graphic_hw_gl_block(ddl->dcl.con, true);
+    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
     glFlush();
+#ifdef CONFIG_GBM
+    graphic_hw_gl_block(ddl->dcl.con, true);
     qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy,
         x, y, w, h,
         G_DBUS_CALL_FLAGS_NONE,
         DBUS_DEFAULT_TIMEOUT, NULL,
         dbus_update_gl_cb,
         g_object_ref(ddl));
-}
-
-static void dbus_scanout_disable(DisplayChangeListener *dcl)
-{
-    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+#endif
 
-    ddl->ds = NULL;
-    qemu_dbus_display1_listener_call_disable(
-        ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+#ifdef WIN32
+    egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
+    dbus_gfx_update(dcl, x, y, w, h);
+#endif
 }
 
+#ifdef CONFIG_GBM
 static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
                                 QemuDmaBuf *dmabuf)
 {
@@ -127,7 +148,8 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
         fd_list,
         NULL, NULL, NULL);
 }
-#endif /* OPENGL & GBM */
+#endif /* GBM */
+#endif /* OPENGL */
 
 #ifdef WIN32
 static bool dbus_scanout_map(DBusDisplayListener *ddl)
@@ -181,7 +203,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
 }
 #endif
 
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
 static void dbus_scanout_texture(DisplayChangeListener *dcl,
                                  uint32_t tex_id,
                                  bool backing_y_0_top,
@@ -190,6 +212,7 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
                                  uint32_t x, uint32_t y,
                                  uint32_t w, uint32_t h)
 {
+#ifdef CONFIG_GBM
     QemuDmaBuf dmabuf = {
         .width = backing_width,
         .height = backing_height,
@@ -212,8 +235,19 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
 
     dbus_scanout_dmabuf(dcl, &dmabuf);
     close(dmabuf.fd);
+#endif
+
+#ifdef WIN32
+    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+    /* there must be a matching gfx_switch before */
+    assert(surface_width(ddl->ds) == w);
+    assert(surface_height(ddl->ds) == h);
+    egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
+#endif
 }
 
+#ifdef CONFIG_GBM
 static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
                                QemuDmaBuf *dmabuf, bool have_hot,
                                uint32_t hot_x, uint32_t hot_y)
@@ -260,7 +294,14 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
         NULL);
 }
 
-static void dbus_cursor_position(DisplayChangeListener *dcl,
+static void dbus_release_dmabuf(DisplayChangeListener *dcl,
+                                QemuDmaBuf *dmabuf)
+{
+    dbus_scanout_disable(dcl);
+}
+#endif /* GBM */
+
+static void dbus_gl_cursor_position(DisplayChangeListener *dcl,
                                  uint32_t pos_x, uint32_t pos_y)
 {
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
@@ -270,19 +311,11 @@ static void dbus_cursor_position(DisplayChangeListener *dcl,
         G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
 }
 
-static void dbus_release_dmabuf(DisplayChangeListener *dcl,
-                                QemuDmaBuf *dmabuf)
-{
-    dbus_scanout_disable(dcl);
-}
-
 static void dbus_scanout_update(DisplayChangeListener *dcl,
                                 uint32_t x, uint32_t y,
                                 uint32_t w, uint32_t h)
 {
-    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
-
-    dbus_call_update_gl(ddl, x, y, w, h);
+    dbus_call_update_gl(dcl, x, y, w, h);
 }
 
 static void dbus_gl_refresh(DisplayChangeListener *dcl)
@@ -296,19 +329,19 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
     }
 
     if (ddl->gl_updates) {
-        dbus_call_update_gl(ddl, 0, 0,
+        dbus_call_update_gl(dcl, 0, 0,
                             surface_width(ddl->ds), surface_height(ddl->ds));
         ddl->gl_updates = 0;
     }
 }
-#endif /* OPENGL & GBM */
+#endif /* OPENGL */
 
 static void dbus_refresh(DisplayChangeListener *dcl)
 {
     graphic_hw_update(dcl->con);
 }
 
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
 static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
                                int x, int y, int w, int h)
 {
@@ -382,7 +415,7 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
         DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
 }
 
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
 static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
                                struct DisplaySurface *new_surface)
 {
@@ -452,7 +485,7 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
         NULL);
 }
 
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
 const DisplayChangeListenerOps dbus_gl_dcl_ops = {
     .dpy_name                = "dbus-gl",
     .dpy_gfx_update          = dbus_gl_gfx_update,
@@ -464,10 +497,12 @@ const DisplayChangeListenerOps dbus_gl_dcl_ops = {
 
     .dpy_gl_scanout_disable  = dbus_scanout_disable,
     .dpy_gl_scanout_texture  = dbus_scanout_texture,
+#ifdef CONFIG_GBM
     .dpy_gl_scanout_dmabuf   = dbus_scanout_dmabuf,
     .dpy_gl_cursor_dmabuf    = dbus_cursor_dmabuf,
-    .dpy_gl_cursor_position  = dbus_cursor_position,
     .dpy_gl_release_dmabuf   = dbus_release_dmabuf,
+#endif
+    .dpy_gl_cursor_position  = dbus_gl_cursor_position,
     .dpy_gl_update           = dbus_scanout_update,
 };
 #endif
@@ -493,6 +528,9 @@ dbus_display_listener_dispose(GObject *object)
 #ifdef WIN32
     g_clear_object(&ddl->map_proxy);
     g_clear_pointer(&ddl->peer_process, CloseHandle);
+#ifdef CONFIG_OPENGL
+    egl_fb_destroy(&ddl->fb);
+#endif
 #endif
 
     G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
@@ -504,7 +542,7 @@ dbus_display_listener_constructed(GObject *object)
     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
 
     ddl->dcl.ops = &dbus_dcl_ops;
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
     if (display_opengl) {
         ddl->dcl.ops = &dbus_gl_dcl_ops;
     }
diff --git a/ui/dbus.c b/ui/dbus.c
index b9e9698503..32f1bbe81a 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -47,10 +47,8 @@ static DBusDisplay *dbus_display;
 static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
                                          QEMUGLParams *params)
 {
-#ifdef CONFIG_GBM
     eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                    qemu_egl_rn_ctx);
-#endif
     return qemu_egl_create_context(dgc, params);
 }
 
@@ -59,9 +57,7 @@ dbus_is_compatible_dcl(DisplayGLCtx *dgc,
                        DisplayChangeListener *dcl)
 {
     return
-#ifdef CONFIG_GBM
         dcl->ops == &dbus_gl_dcl_ops ||
-#endif
         dcl->ops == &dbus_console_dcl_ops;
 }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 28/33] ui/dbus: add some GL traces
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (26 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 27/33] ui/dbus: add GL support on win32 marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 29/33] virtio-gpu-virgl: teach it to get the QEMU EGL display marcandre.lureau
                   ` (4 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-17-marcandre.lureau@redhat.com>
---
 ui/dbus-listener.c | 6 ++++++
 ui/trace-events    | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index e92eff66e3..8605dffd8a 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -102,6 +102,8 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
 {
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
 
+    trace_dbus_update_gl(x, y, w, h);
+
     glFlush();
 #ifdef CONFIG_GBM
     graphic_hw_gl_block(ddl->dcl.con, true);
@@ -212,6 +214,8 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
                                  uint32_t x, uint32_t y,
                                  uint32_t w, uint32_t h)
 {
+    trace_dbus_scanout_texture(tex_id, backing_y_0_top,
+                               backing_width, backing_height, x, y, w, h);
 #ifdef CONFIG_GBM
     QemuDmaBuf dmabuf = {
         .width = backing_width,
@@ -421,6 +425,8 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
 {
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
 
+    trace_dbus_gl_gfx_switch(new_surface);
+
     ddl->ds = new_surface;
     if (ddl->ds) {
         int width = surface_width(ddl->ds);
diff --git a/ui/trace-events b/ui/trace-events
index a71895c479..fe58675163 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -156,6 +156,9 @@ dbus_mouse_set_pos(unsigned int x, unsigned int y) "x=%u, y=%u"
 dbus_mouse_rel_motion(int dx, int dy) "dx=%d, dy=%d"
 dbus_touch_send_event(unsigned int kind, uint32_t num_slot, uint32_t x, uint32_t y) "kind=%u, num_slot=%u, x=%d, y=%d"
 dbus_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
+dbus_update_gl(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
 dbus_clipboard_grab_failed(void) ""
 dbus_clipboard_register(const char *bus_name) "peer %s"
 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_gl_gfx_switch(void *p) "surf: %p"
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 29/33] virtio-gpu-virgl: teach it to get the QEMU EGL display
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (27 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 28/33] ui/dbus: add some GL traces marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 30/33] ui/egl: query ANGLE d3d device marcandre.lureau
                   ` (3 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann,
	Michael S. Tsirkin

From: Marc-André Lureau <marcandre.lureau@redhat.com>

virgl offers a few features that require to have access to the
underlying EGLDisplay. This is the case for the D3D texture sharing support.

The API callback is merged for virgl 1.0:
https://gitlab.freedesktop.org/virgl/virglrenderer/-/merge_requests/1113

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-18-marcandre.lureau@redhat.com>
---
 hw/display/virtio-gpu-virgl.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 1c47603d40..9831c482e5 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -18,9 +18,17 @@
 #include "hw/virtio/virtio.h"
 #include "hw/virtio/virtio-gpu.h"
 
+#include "ui/egl-helpers.h"
+
 #include <virglrenderer.h>
 
-static struct virgl_renderer_callbacks virtio_gpu_3d_cbs;
+#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
+static void *
+virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
+{
+    return qemu_egl_display;
+}
+#endif
 
 static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
                                          struct virtio_gpu_ctrl_command *cmd)
@@ -608,6 +616,13 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
 {
     int ret;
 
+#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
+    if (qemu_egl_display) {
+        virtio_gpu_3d_cbs.version = 4;
+        virtio_gpu_3d_cbs.get_egl_display = virgl_get_egl_display;
+    }
+#endif
+
     ret = virgl_renderer_init(g, 0, &virtio_gpu_3d_cbs);
     if (ret != 0) {
         error_report("virgl could not be initialized: %d", ret);
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 30/33] ui/egl: query ANGLE d3d device
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (28 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 29/33] virtio-gpu-virgl: teach it to get the QEMU EGL display marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 31/33] ui: add optional d3d texture pointer to scanout texture marcandre.lureau
                   ` (2 subsequent siblings)
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Check if ANGLE is being used with D3D backend.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-19-marcandre.lureau@redhat.com>
---
 include/ui/egl-helpers.h |  1 +
 ui/egl-helpers.c         | 32 +++++++++++++++++++++++++++++++-
 ui/trace-events          |  3 +++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 6e2f0c49a6..4b8c0d2281 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -12,6 +12,7 @@
 extern EGLDisplay *qemu_egl_display;
 extern EGLConfig qemu_egl_config;
 extern DisplayGLMode qemu_egl_mode;
+extern bool qemu_egl_angle_d3d;
 
 typedef struct egl_fb {
     int width;
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index f38800e920..8f9fbf583e 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -15,16 +15,19 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "qemu/osdep.h"
+
 #include "qemu/drm.h"
 #include "qemu/error-report.h"
 #include "ui/console.h"
 #include "ui/egl-helpers.h"
 #include "sysemu/sysemu.h"
 #include "qapi/error.h"
+#include "trace.h"
 
 EGLDisplay *qemu_egl_display;
 EGLConfig qemu_egl_config;
 DisplayGLMode qemu_egl_mode;
+bool qemu_egl_angle_d3d;
 
 /* ------------------------------------------------------------------ */
 
@@ -553,7 +556,34 @@ int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode)
     if (mode == DISPLAYGL_MODE_ON) {
         mode = DISPLAYGL_MODE_ES;
     }
-    return qemu_egl_init_dpy(dpy, 0, mode);
+
+    if (qemu_egl_init_dpy(dpy, 0, mode) < 0) {
+        return -1;
+    }
+
+#ifdef EGL_D3D11_DEVICE_ANGLE
+    if (epoxy_has_egl_extension(qemu_egl_display, "EGL_EXT_device_query")) {
+        EGLDeviceEXT device;
+        void *d3d11_device;
+
+        if (!eglQueryDisplayAttribEXT(qemu_egl_display,
+                                      EGL_DEVICE_EXT,
+                                      (EGLAttrib *)&device)) {
+            return 0;
+        }
+
+        if (!eglQueryDeviceAttribEXT(device,
+                                     EGL_D3D11_DEVICE_ANGLE,
+                                     (EGLAttrib *)&d3d11_device)) {
+            return 0;
+        }
+
+        trace_egl_init_d3d11_device(device);
+        qemu_egl_angle_d3d = device != NULL;
+    }
+#endif
+
+    return 0;
 }
 #endif
 
diff --git a/ui/trace-events b/ui/trace-events
index fe58675163..76b19a2995 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -162,3 +162,6 @@ dbus_clipboard_register(const char *bus_name) "peer %s"
 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_gl_gfx_switch(void *p) "surf: %p"
+
+# egl-helpers.c
+egl_init_d3d11_device(void *p) "d3d device: %p"
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 31/33] ui: add optional d3d texture pointer to scanout texture
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (29 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 30/33] ui/egl: query ANGLE d3d device marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 32/33] virtio-gpu-virgl: use D3D11_SHARE_TEXTURE when available marcandre.lureau
  2023-06-27 13:02 ` [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible marcandre.lureau
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Michael S. Tsirkin,
	Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The following patch will get the underlying D3D11 Texture2D from the
virgl renderer scanout. Pass it along to the texture scanout callbacks
as a priliminary step, to simplify review.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-20-marcandre.lureau@redhat.com>
---
 include/ui/console.h          |  7 +++++--
 include/ui/gtk.h              |  6 ++++--
 include/ui/sdl2.h             |  3 ++-
 hw/display/virtio-gpu-virgl.c |  4 +++-
 ui/console.c                  | 11 +++++++----
 ui/dbus-console.c             |  3 ++-
 ui/dbus-listener.c            |  5 +++--
 ui/egl-headless.c             |  5 +++--
 ui/gtk-egl.c                  |  5 +++--
 ui/gtk-gl-area.c              |  5 +++--
 ui/sdl2-gl.c                  |  3 ++-
 ui/spice-display.c            |  3 ++-
 12 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 2ab0c7112a..f27b2aad4f 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -132,6 +132,7 @@ typedef struct ScanoutTexture {
     uint32_t y;
     uint32_t width;
     uint32_t height;
+    void *d3d_tex2d;
 } ScanoutTexture;
 
 typedef struct DisplaySurface {
@@ -270,7 +271,8 @@ typedef struct DisplayChangeListenerOps {
                                    uint32_t backing_width,
                                    uint32_t backing_height,
                                    uint32_t x, uint32_t y,
-                                   uint32_t w, uint32_t h);
+                                   uint32_t w, uint32_t h,
+                                   void *d3d_tex2d);
     /* optional (default to true if has dpy_gl_scanout_dmabuf) */
     bool (*dpy_has_dmabuf)(DisplayChangeListener *dcl);
     /* optional */
@@ -378,7 +380,8 @@ void dpy_gl_scanout_disable(QemuConsole *con);
 void dpy_gl_scanout_texture(QemuConsole *con,
                             uint32_t backing_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);
+                            uint32_t x, uint32_t y, uint32_t w, uint32_t h,
+                            void *d3d_tex2d);
 void dpy_gl_scanout_dmabuf(QemuConsole *con,
                            QemuDmaBuf *dmabuf);
 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index ae0f53740d..aa3d637029 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -175,7 +175,8 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
                             uint32_t backing_width,
                             uint32_t backing_height,
                             uint32_t x, uint32_t y,
-                            uint32_t w, uint32_t h);
+                            uint32_t w, uint32_t h,
+                            void *d3d_tex2d);
 void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
                            QemuDmaBuf *dmabuf);
 void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl,
@@ -211,7 +212,8 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
                                 uint32_t backing_width,
                                 uint32_t backing_height,
                                 uint32_t x, uint32_t y,
-                                uint32_t w, uint32_t h);
+                                uint32_t w, uint32_t h,
+                                void *d3d_tex2d);
 void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);
 void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
                               uint32_t x, uint32_t y, uint32_t w, uint32_t h);
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index 8fb7e08262..e3acc7c82a 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -90,7 +90,8 @@ void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
                              uint32_t backing_width,
                              uint32_t backing_height,
                              uint32_t x, uint32_t y,
-                             uint32_t w, uint32_t h);
+                             uint32_t w, uint32_t h,
+                             void *d3d_tex2d);
 void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
                            uint32_t x, uint32_t y, uint32_t w, uint32_t h);
 
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 9831c482e5..8fa9809371 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -154,6 +154,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
 {
     struct virtio_gpu_set_scanout ss;
     struct virgl_renderer_resource_info info;
+    void *d3d_tex2d = NULL;
     int ret;
 
     VIRTIO_GPU_FILL_CMD(ss);
@@ -186,7 +187,8 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
             g->parent_obj.scanout[ss.scanout_id].con, info.tex_id,
             info.flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP,
             info.width, info.height,
-            ss.r.x, ss.r.y, ss.r.width, ss.r.height);
+            ss.r.x, ss.r.y, ss.r.width, ss.r.height,
+            d3d_tex2d);
     } else {
         dpy_gfx_replace_surface(
             g->parent_obj.scanout[ss.scanout_id].con, NULL);
diff --git a/ui/console.c b/ui/console.c
index 4957110723..c1544e0fb8 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1223,7 +1223,8 @@ static void displaychangelistener_display_console(DisplayChangeListener *dcl,
                                          con->scanout.texture.x,
                                          con->scanout.texture.y,
                                          con->scanout.texture.width,
-                                         con->scanout.texture.height);
+                                         con->scanout.texture.height,
+                                         con->scanout.texture.d3d_tex2d);
     }
 }
 
@@ -2115,7 +2116,8 @@ void dpy_gl_scanout_texture(QemuConsole *con,
                             uint32_t backing_width,
                             uint32_t backing_height,
                             uint32_t x, uint32_t y,
-                            uint32_t width, uint32_t height)
+                            uint32_t width, uint32_t height,
+                            void *d3d_tex2d)
 {
     DisplayState *s = con->ds;
     DisplayChangeListener *dcl;
@@ -2123,7 +2125,7 @@ void dpy_gl_scanout_texture(QemuConsole *con,
     con->scanout.kind = SCANOUT_TEXTURE;
     con->scanout.texture = (ScanoutTexture) {
         backing_id, backing_y_0_top, backing_width, backing_height,
-        x, y, width, height
+        x, y, width, height, d3d_tex2d,
     };
     QLIST_FOREACH(dcl, &s->listeners, next) {
         if (con != (dcl->con ? dcl->con : active_console)) {
@@ -2133,7 +2135,8 @@ void dpy_gl_scanout_texture(QemuConsole *con,
             dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
                                              backing_y_0_top,
                                              backing_width, backing_height,
-                                             x, y, width, height);
+                                             x, y, width, height,
+                                             d3d_tex2d);
         }
     }
 }
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index aaa9d3b0b3..e19774f985 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -98,7 +98,8 @@ dbus_gl_scanout_texture(DisplayChangeListener *dcl,
                         uint32_t backing_width,
                         uint32_t backing_height,
                         uint32_t x, uint32_t y,
-                        uint32_t w, uint32_t h)
+                        uint32_t w, uint32_t h,
+                        void *d3d_tex2d)
 {
     DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
 
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 8605dffd8a..80c0fca9df 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -212,7 +212,8 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
                                  uint32_t backing_width,
                                  uint32_t backing_height,
                                  uint32_t x, uint32_t y,
-                                 uint32_t w, uint32_t h)
+                                 uint32_t w, uint32_t h,
+                                 void *d3d_tex2d)
 {
     trace_dbus_scanout_texture(tex_id, backing_y_0_top,
                                backing_width, backing_height, x, y, w, h);
@@ -434,7 +435,7 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
 
         /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
         dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false,
-                             width, height, 0, 0, width, height);
+                             width, height, 0, 0, width, height, NULL);
     }
 }
 #endif
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index e4177206f2..d5637dadb2 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -61,7 +61,8 @@ static void egl_scanout_texture(DisplayChangeListener *dcl,
                                 uint32_t backing_width,
                                 uint32_t backing_height,
                                 uint32_t x, uint32_t y,
-                                uint32_t w, uint32_t h)
+                                uint32_t w, uint32_t h,
+                                void *d3d_tex2d)
 {
     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
 
@@ -91,7 +92,7 @@ static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
 
     egl_scanout_texture(dcl, dmabuf->texture,
                         false, dmabuf->width, dmabuf->height,
-                        0, 0, dmabuf->width, dmabuf->height);
+                        0, 0, dmabuf->width, dmabuf->height, NULL);
 }
 
 static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 64dc0eeec8..d59b8cd7d7 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -224,7 +224,8 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
                             uint32_t backing_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)
+                            uint32_t w, uint32_t h,
+                            void *d3d_tex2d)
 {
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 
@@ -259,7 +260,7 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
     gd_egl_scanout_texture(dcl, dmabuf->texture,
                            dmabuf->y0_top, dmabuf->width, dmabuf->height,
                            dmabuf->x, dmabuf->y, dmabuf->scanout_width,
-                           dmabuf->scanout_height);
+                           dmabuf->scanout_height, NULL);
 
     if (dmabuf->allow_fences) {
         vc->gfx.guest_fb.dmabuf = dmabuf;
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 1605818bd1..7367dfd793 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -244,7 +244,8 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
                                 uint32_t backing_width,
                                 uint32_t backing_height,
                                 uint32_t x, uint32_t y,
-                                uint32_t w, uint32_t h)
+                                uint32_t w, uint32_t h,
+                                void *d3d_tex2d)
 {
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 
@@ -300,7 +301,7 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
     gd_gl_area_scanout_texture(dcl, dmabuf->texture,
                                dmabuf->y0_top, dmabuf->width, dmabuf->height,
                                dmabuf->x, dmabuf->y, dmabuf->scanout_width,
-                               dmabuf->scanout_height);
+                               dmabuf->scanout_height, NULL);
 
     if (dmabuf->allow_fences) {
         vc->gfx.guest_fb.dmabuf = dmabuf;
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index bbfa70eac3..28d796607c 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -205,7 +205,8 @@ void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
                              uint32_t backing_width,
                              uint32_t backing_height,
                              uint32_t x, uint32_t y,
-                             uint32_t w, uint32_t h)
+                             uint32_t w, uint32_t h,
+                             void *d3d_tex2d)
 {
     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 5bee19a7f9..3f3f8013d8 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -935,7 +935,8 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
                                           uint32_t backing_width,
                                           uint32_t backing_height,
                                           uint32_t x, uint32_t y,
-                                          uint32_t w, uint32_t h)
+                                          uint32_t w, uint32_t h,
+                                          void *d3d_tex2d)
 {
     SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
     EGLint stride = 0, fourcc = 0;
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 32/33] virtio-gpu-virgl: use D3D11_SHARE_TEXTURE when available
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (30 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 31/33] ui: add optional d3d texture pointer to scanout texture marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-27 13:02 ` [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible marcandre.lureau
  32 siblings, 0 replies; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann,
	Michael S. Tsirkin, Paolo Bonzini, Daniel P. Berrangé,
	Thomas Huth, Philippe Mathieu-Daudé

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Enable D3D texture sharing when possible, and pass it to the texture
display callbacks.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-21-marcandre.lureau@redhat.com>
---
 meson.build                   |  6 ++++++
 hw/display/virtio-gpu-virgl.c | 24 +++++++++++++++++++-----
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/meson.build b/meson.build
index 9a1ce43471..1631e60a3b 100644
--- a/meson.build
+++ b/meson.build
@@ -1072,6 +1072,12 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
   virgl = dependency('virglrenderer',
                      method: 'pkg-config',
                      required: get_option('virglrenderer'))
+  if virgl.found()
+    config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT',
+                         cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d',
+                                       prefix: '#include <virglrenderer.h>',
+                                       dependencies: virgl))
+  endif
 endif
 blkio = not_found
 if not get_option('blkio').auto() or have_block
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 8fa9809371..8bb7a2c21f 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -153,8 +153,6 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
                                   struct virtio_gpu_ctrl_command *cmd)
 {
     struct virtio_gpu_set_scanout ss;
-    struct virgl_renderer_resource_info info;
-    void *d3d_tex2d = NULL;
     int ret;
 
     VIRTIO_GPU_FILL_CMD(ss);
@@ -169,10 +167,20 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
     }
     g->parent_obj.enable = 1;
 
-    memset(&info, 0, sizeof(info));
-
     if (ss.resource_id && ss.r.width && ss.r.height) {
+        struct virgl_renderer_resource_info info;
+        void *d3d_tex2d = NULL;
+
+#ifdef HAVE_VIRGL_D3D_INFO_EXT
+        struct virgl_renderer_resource_info_ext ext;
+        memset(&ext, 0, sizeof(ext));
+        ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext);
+        info = ext.base;
+        d3d_tex2d = ext.d3d_tex2d;
+#else
+        memset(&info, 0, sizeof(info));
         ret = virgl_renderer_resource_get_info(ss.resource_id, &info);
+#endif
         if (ret == -1) {
             qemu_log_mask(LOG_GUEST_ERROR,
                           "%s: illegal resource specified %d\n",
@@ -617,6 +625,7 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
 int virtio_gpu_virgl_init(VirtIOGPU *g)
 {
     int ret;
+    uint32_t flags = 0;
 
 #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
     if (qemu_egl_display) {
@@ -624,8 +633,13 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
         virtio_gpu_3d_cbs.get_egl_display = virgl_get_egl_display;
     }
 #endif
+#ifdef VIRGL_RENDERER_D3D11_SHARE_TEXTURE
+    if (qemu_egl_angle_d3d) {
+        flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE;
+    }
+#endif
 
-    ret = virgl_renderer_init(g, 0, &virtio_gpu_3d_cbs);
+    ret = virgl_renderer_init(g, flags, &virtio_gpu_3d_cbs);
     if (ret != 0) {
         error_report("virgl could not be initialized: %d", ret);
         return ret;
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible
  2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
                   ` (31 preceding siblings ...)
  2023-06-27 13:02 ` [PULL 32/33] virtio-gpu-virgl: use D3D11_SHARE_TEXTURE when available marcandre.lureau
@ 2023-06-27 13:02 ` marcandre.lureau
  2023-06-29  7:40   ` Richard Henderson
  32 siblings, 1 reply; 46+ messages in thread
From: marcandre.lureau @ 2023-06-27 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

When the client implements "org.qemu.Display1.Listener.Win32.D3d11" and
we are running on ANGLE/win32, share the scanout texture with the peer
process, and draw with ScanoutTexture2d/UpdateTexture2d methods.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230606115658.677673-22-marcandre.lureau@redhat.com>
---
 ui/dbus-listener.c   | 299 ++++++++++++++++++++++++++++++++++++++-----
 ui/dbus-display1.xml |  56 +++++++-
 2 files changed, 324 insertions(+), 31 deletions(-)

diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 80c0fca9df..e10162b279 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -23,11 +23,16 @@
  */
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
 #include "sysemu/sysemu.h"
 #include "dbus.h"
 #ifdef G_OS_UNIX
 #include <gio/gunixfdlist.h>
 #endif
+#ifdef WIN32
+#include <d3d11.h>
+#include <dxgi1_2.h>
+#endif
 
 #ifdef CONFIG_OPENGL
 #include "ui/shader.h"
@@ -39,6 +44,12 @@
 static void dbus_gfx_switch(DisplayChangeListener *dcl,
                             struct DisplaySurface *new_surface);
 
+enum share_kind {
+    SHARE_KIND_NONE,
+    SHARE_KIND_MAPPED,
+    SHARE_KIND_D3DTEX,
+};
+
 struct _DBusDisplayListener {
     GObject parent;
 
@@ -50,6 +61,8 @@ struct _DBusDisplayListener {
 
     DisplayChangeListener dcl;
     DisplaySurface *ds;
+    enum share_kind ds_share;
+
     int gl_updates;
 
     bool ds_mapped;
@@ -57,7 +70,9 @@ struct _DBusDisplayListener {
 
 #ifdef WIN32
     QemuDBusDisplay1ListenerWin32Map *map_proxy;
+    QemuDBusDisplay1ListenerWin32D3d11 *d3d11_proxy;
     HANDLE peer_process;
+    ID3D11Texture2D *d3d_texture;
 #ifdef CONFIG_OPENGL
     egl_fb fb;
 #endif
@@ -74,28 +89,120 @@ static void dbus_scanout_disable(DisplayChangeListener *dcl)
 {
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
 
-    ddl->ds = NULL;
     qemu_dbus_display1_listener_call_disable(
         ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
 }
 
-#ifdef CONFIG_GBM
+#ifdef WIN32
+static bool d3d_texture2d_share(ID3D11Texture2D *d3d_texture,
+                                HANDLE *handle, Error **errp)
+{
+    IDXGIResource1 *dxgiResource = NULL;
+    HRESULT hr;
+
+    hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
+                                             &IID_IDXGIResource1,
+                                             (void **)&dxgiResource);
+    if (FAILED(hr)) {
+        goto fail;
+    }
+
+    hr = dxgiResource->lpVtbl->CreateSharedHandle(
+        dxgiResource,
+        NULL,
+        DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
+        NULL,
+        handle
+        );
+
+    dxgiResource->lpVtbl->Release(dxgiResource);
+
+    if (SUCCEEDED(hr)) {
+        return true;
+    }
+
+fail:
+    error_setg_win32(errp, GetLastError(), "failed to create shared handle");
+    return false;
+}
+
+static bool d3d_texture2d_acquire0(ID3D11Texture2D *d3d_texture, Error **errp)
+{
+    IDXGIKeyedMutex *dxgiMutex = NULL;
+    HRESULT hr;
+
+    hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
+                                             &IID_IDXGIKeyedMutex,
+                                             (void **)&dxgiMutex);
+    if (FAILED(hr)) {
+        goto fail;
+    }
+
+    hr = dxgiMutex->lpVtbl->AcquireSync(dxgiMutex, 0, INFINITE);
+
+    dxgiMutex->lpVtbl->Release(dxgiMutex);
+
+    if (SUCCEEDED(hr)) {
+        return true;
+    }
+
+fail:
+    error_setg_win32(errp, GetLastError(), "failed to acquire texture mutex");
+    return false;
+}
+
+static bool d3d_texture2d_release0(ID3D11Texture2D *d3d_texture, Error **errp)
+{
+    IDXGIKeyedMutex *dxgiMutex = NULL;
+    HRESULT hr;
+
+    hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
+                                             &IID_IDXGIKeyedMutex,
+                                             (void **)&dxgiMutex);
+    if (FAILED(hr)) {
+        goto fail;
+    }
+
+    hr = dxgiMutex->lpVtbl->ReleaseSync(dxgiMutex, 0);
+
+    dxgiMutex->lpVtbl->Release(dxgiMutex);
+
+    if (SUCCEEDED(hr)) {
+        return true;
+    }
+
+fail:
+    error_setg_win32(errp, GetLastError(), "failed to release texture mutex");
+    return false;
+}
+#endif /* WIN32 */
+
 static void dbus_update_gl_cb(GObject *source_object,
-                           GAsyncResult *res,
-                           gpointer user_data)
+                              GAsyncResult *res,
+                              gpointer user_data)
 {
     g_autoptr(GError) err = NULL;
     DBusDisplayListener *ddl = user_data;
+    bool success;
+
+#ifdef CONFIG_GBM
+    success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
+        ddl->proxy, res, &err);
+#endif
+
+#ifdef WIN32
+    success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
+        ddl->d3d11_proxy, res, &err);
+    d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
+#endif
 
-    if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy,
-                                                               res, &err)) {
+    if (!success) {
         error_report("Failed to call update: %s", err->message);
     }
 
     graphic_hw_gl_block(ddl->dcl.con, false);
     g_object_unref(ddl);
 }
-#endif
 
 static void dbus_call_update_gl(DisplayChangeListener *dcl,
                                 int x, int y, int w, int h)
@@ -116,8 +223,31 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
 #endif
 
 #ifdef WIN32
-    egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
-    dbus_gfx_update(dcl, x, y, w, h);
+    switch (ddl->ds_share) {
+    case SHARE_KIND_MAPPED:
+        egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
+        dbus_gfx_update(dcl, x, y, w, h);
+        break;
+    case SHARE_KIND_D3DTEX:
+        Error *err = NULL;
+        assert(ddl->d3d_texture);
+
+        graphic_hw_gl_block(ddl->dcl.con, true);
+        if (!d3d_texture2d_release0(ddl->d3d_texture, &err)) {
+            error_report_err(err);
+            return;
+        }
+        qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
+            ddl->d3d11_proxy,
+            x, y, w, h,
+            G_DBUS_CALL_FLAGS_NONE,
+            DBUS_DEFAULT_TIMEOUT, NULL,
+            dbus_update_gl_cb,
+            g_object_ref(ddl));
+        break;
+    default:
+        g_warn_if_reached();
+    }
 #endif
 }
 
@@ -160,7 +290,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
     BOOL success;
     HANDLE target_handle;
 
-    if (ddl->ds_mapped) {
+    if (ddl->ds_share == SHARE_KIND_MAPPED) {
         return true;
     }
 
@@ -199,7 +329,69 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
         return false;
     }
 
-    ddl->ds_mapped = true;
+    ddl->ds_share = SHARE_KIND_MAPPED;
+
+    return true;
+}
+
+static bool
+dbus_scanout_share_d3d_texture(
+    DBusDisplayListener *ddl,
+    ID3D11Texture2D *tex,
+    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)
+{
+    Error *err = NULL;
+    BOOL success;
+    HANDLE share_handle, target_handle;
+
+    if (!d3d_texture2d_release0(tex, &err)) {
+        error_report_err(err);
+        return false;
+    }
+
+    if (!d3d_texture2d_share(tex, &share_handle, &err)) {
+        error_report_err(err);
+        return false;
+    }
+
+    success = DuplicateHandle(
+        GetCurrentProcess(),
+        share_handle,
+        ddl->peer_process,
+        &target_handle,
+        0,
+        FALSE, DUPLICATE_SAME_ACCESS);
+    if (!success) {
+        g_autofree char *msg = g_win32_error_message(GetLastError());
+        g_debug("Failed to DuplicateHandle: %s", msg);
+        CloseHandle(share_handle);
+        return false;
+    }
+
+    qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
+        ddl->d3d11_proxy,
+        GPOINTER_TO_INT(target_handle),
+        backing_width,
+        backing_height,
+        backing_y_0_top,
+        x, y, w, h,
+        G_DBUS_CALL_FLAGS_NONE,
+        -1,
+        NULL, NULL, NULL);
+
+    CloseHandle(share_handle);
+
+    if (!d3d_texture2d_acquire0(tex, &err)) {
+        error_report_err(err);
+        return false;
+    }
+
+    ddl->d3d_texture = tex;
+    ddl->ds_share = SHARE_KIND_D3DTEX;
 
     return true;
 }
@@ -248,7 +440,14 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
     /* there must be a matching gfx_switch before */
     assert(surface_width(ddl->ds) == w);
     assert(surface_height(ddl->ds) == h);
-    egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
+
+    if (d3d_tex2d) {
+        dbus_scanout_share_d3d_texture(ddl, d3d_tex2d, backing_y_0_top,
+                                       backing_width, backing_height, x, y, w, h);
+    } else {
+        dbus_scanout_map(ddl);
+        egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
+    }
 #endif
 }
 
@@ -429,6 +628,7 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
     trace_dbus_gl_gfx_switch(new_surface);
 
     ddl->ds = new_surface;
+    ddl->ds_share = SHARE_KIND_NONE;
     if (ddl->ds) {
         int width = surface_width(ddl->ds);
         int height = surface_height(ddl->ds);
@@ -446,13 +646,7 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl,
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
 
     ddl->ds = new_surface;
-#ifdef WIN32
-    ddl->ds_mapped = false;
-#endif
-    if (!ddl->ds) {
-        /* why not call disable instead? */
-        return;
-    }
+    ddl->ds_share = SHARE_KIND_NONE;
 }
 
 static void dbus_mouse_set(DisplayChangeListener *dcl,
@@ -534,6 +728,7 @@ dbus_display_listener_dispose(GObject *object)
     g_clear_object(&ddl->proxy);
 #ifdef WIN32
     g_clear_object(&ddl->map_proxy);
+    g_clear_object(&ddl->d3d11_proxy);
     g_clear_pointer(&ddl->peer_process, CloseHandle);
 #ifdef CONFIG_OPENGL
     egl_fb_destroy(&ddl->fb);
@@ -598,12 +793,10 @@ dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
 
     return implements;
 }
-#endif
 
-static void
-dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
+static bool
+dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
 {
-#ifdef WIN32
     g_autoptr(GError) err = NULL;
     GDBusConnection *conn;
     GIOStream *stream;
@@ -611,15 +804,15 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
     g_autoptr(GCredentials) creds = NULL;
     DWORD *pid;
 
-    if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
-        return;
+    if (ddl->peer_process) {
+        return true;
     }
 
     conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy));
     stream = g_dbus_connection_get_stream(conn);
 
     if (!G_IS_UNIX_CONNECTION(stream)) {
-        return;
+        return false;
     }
 
     sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream));
@@ -627,14 +820,14 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
 
     if (!creds) {
         g_debug("Failed to get peer credentials: %s", err->message);
-        return;
+        return false;
     }
 
     pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID);
 
     if (pid == NULL) {
         g_debug("Failed to get peer PID");
-        return;
+        return false;
     }
 
     ddl->peer_process = OpenProcess(
@@ -644,11 +837,58 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
     if (!ddl->peer_process) {
         g_autofree char *msg = g_win32_error_message(GetLastError());
         g_debug("Failed to OpenProcess: %s", msg);
+        return false;
+    }
+
+    return true;
+}
+#endif
+
+static void
+dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
+{
+#ifdef WIN32
+    g_autoptr(GError) err = NULL;
+
+    if (!dbus_display_listener_implements(ddl,
+            "org.qemu.Display1.Listener.Win32.D3d11")) {
+        return;
+    }
+
+    if (!dbus_display_listener_setup_peer_process(ddl)) {
+        return;
+    }
+
+    ddl->d3d11_proxy =
+        qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl->conn,
+            G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+            NULL,
+            "/org/qemu/Display1/Listener",
+            NULL,
+            &err);
+    if (!ddl->d3d11_proxy) {
+        g_debug("Failed to setup win32 d3d11 proxy: %s", err->message);
+        return;
+    }
+#endif
+}
+
+static void
+dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
+{
+#ifdef WIN32
+    g_autoptr(GError) err = NULL;
+
+    if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
+        return;
+    }
+
+    if (!dbus_display_listener_setup_peer_process(ddl)) {
         return;
     }
 
     ddl->map_proxy =
-        qemu_dbus_display1_listener_win32_map_proxy_new_sync(conn,
+        qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl->conn,
             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
             NULL,
             "/org/qemu/Display1/Listener",
@@ -692,6 +932,7 @@ dbus_display_listener_new(const char *bus_name,
     ddl->console = console;
 
     dbus_display_listener_setup_shared_map(ddl);
+    dbus_display_listener_setup_d3d11(ddl);
 
     con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
     assert(con);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index 7233286b28..f0e2fac212 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -472,8 +472,9 @@
   <!--
       org.qemu.Display1.Listener.Win32.Map:
 
-      This client-side interface can complement org.qemu.Display1.Listener on
-      ``/org/qemu/Display1/Listener`` for Windows specific methods.
+      This optional client-side interface can complement
+      org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
+      specific shared memory scanouts.
   -->
   <interface name="org.qemu.Display1.Listener.Win32.Map">
     <!--
@@ -513,6 +514,57 @@
     </method>
   </interface>
 
+  <!--
+      org.qemu.Display1.Listener.Win32.D3d11:
+
+      This optional client-side interface can complement
+      org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
+      specific Direct3D texture sharing of the scanouts.
+  -->
+  <interface name="org.qemu.Display1.Listener.Win32.D3d11">
+    <!--
+        ScanoutTexture2d:
+        @handle: the NT handle for the shared texture (to be opened back with ID3D11Device1::OpenSharedResource1).
+        @texture_width: texture width, in pixels.
+        @texture_height: texture height, in pixels.
+        @y0_top: whether Y position 0 is the top or not.
+        @x: the X scanout position, in pixels.
+        @y: the Y scanout position, in pixels.
+        @width: the scanout width, in pixels.
+        @height: the scanout height, in pixels.
+
+        Resize and update the display content with a Direct3D 11 2D texture.
+        You must acquire and release the associated KeyedMutex 0 during rendering.
+    -->
+    <method name="ScanoutTexture2d">
+      <arg type="t" name="handle" direction="in"/>
+      <arg type="u" name="texture_width" direction="in"/>
+      <arg type="u" name="texture_height" direction="in"/>
+      <arg type="b" name="y0_top" direction="in"/>
+      <arg type="u" name="x" direction="in"/>
+      <arg type="u" name="y" direction="in"/>
+      <arg type="u" name="width" direction="in"/>
+      <arg type="u" name="height" direction="in"/>
+    </method>
+
+    <!--
+        UpdateTexture2d:
+        @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 Direct3D 2D texture and the given region.
+        You must acquire and release the associated KeyedMutex 0 during rendering.
+    -->
+    <method name="UpdateTexture2d">
+      <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>
+
   <!--
       org.qemu.Display1.Clipboard:
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer
  2023-06-27 13:02 ` [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer marcandre.lureau
@ 2023-06-27 15:04   ` Richard Henderson
  2023-06-27 15:10     ` Marc-André Lureau
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Henderson @ 2023-06-27 15:04 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel
  Cc: Keqian Zhu, Michael S. Tsirkin, Gerd Hoffmann

On 6/27/23 15:02, marcandre.lureau@redhat.com wrote:
> From: Keqian Zhu via <qemu-devel@nongnu.org>

You need to fix the author for this patch.


r~


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer
  2023-06-27 15:04   ` Richard Henderson
@ 2023-06-27 15:10     ` Marc-André Lureau
  2023-06-28  9:22       ` Richard Henderson
  0 siblings, 1 reply; 46+ messages in thread
From: Marc-André Lureau @ 2023-06-27 15:10 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, Keqian Zhu, Michael S. Tsirkin, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 844 bytes --]

Hi

On Tue, Jun 27, 2023 at 5:04 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 6/27/23 15:02, marcandre.lureau@redhat.com wrote:
> > From: Keqian Zhu via <qemu-devel@nongnu.org>
>
> You need to fix the author for this patch.
>
>
>
ok done, do you want me to re-send the whole PR or is that enough?

The following changes since commit 4329d049d5b8d4af71c6b399d64a6d1b98856318:

  Merge tag 'pull-tcg-20230626' of https://gitlab.com/rth7680/qemu into
staging (2023-06-26 17:40:38 +0200)

are available in the Git repository at:

  https://gitlab.com/marcandre.lureau/qemu.git tags/ui-pull-request

for you to fetch changes up to de1f8ce0abb8c43d1e6a00c31c6d24dfe0505b92:

  ui/dbus: use shared D3D11 Texture2D when possible (2023-06-27 17:08:56
+0200)



> r~
>
>

-- 
Marc-André Lureau

[-- Attachment #2: Type: text/html, Size: 1749 bytes --]

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 10/33] ui/gtk: set the area of the scanout texture correctly
  2023-06-27 13:02 ` [PULL 10/33] ui/gtk: set the area of the scanout texture correctly marcandre.lureau
@ 2023-06-27 17:46   ` Michael Tokarev
  0 siblings, 0 replies; 46+ messages in thread
From: Michael Tokarev @ 2023-06-27 17:46 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel
  Cc: richard.henderson, Dongwon Kim, Gerd Hoffmann, Vivek Kasireddy,
	qemu-stable

27.06.2023 16:02, marcandre.lureau@redhat.com wrote:
> From: Dongwon Kim <dongwon.kim@intel.com>
> 
> x and y offsets and width and height of the scanout texture
> is not correctly configured in case guest scanout frame is
> dmabuf.

Is this a -stable material too?

Thanks,

/mjt




^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer
  2023-06-27 15:10     ` Marc-André Lureau
@ 2023-06-28  9:22       ` Richard Henderson
  0 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2023-06-28  9:22 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Keqian Zhu, Michael S. Tsirkin, Gerd Hoffmann

On 6/27/23 17:10, Marc-André Lureau wrote:
> Hi
> 
> On Tue, Jun 27, 2023 at 5:04 PM Richard Henderson <richard.henderson@linaro.org 
> <mailto:richard.henderson@linaro.org>> wrote:
> 
>     On 6/27/23 15:02, marcandre.lureau@redhat.com <mailto:marcandre.lureau@redhat.com> wrote:
>      > From: Keqian Zhu via <qemu-devel@nongnu.org <mailto:qemu-devel@nongnu.org>>
> 
>     You need to fix the author for this patch.
> 
> 
> 
> ok done, do you want me to re-send the whole PR or is that enough?
> 
> The following changes since commit 4329d049d5b8d4af71c6b399d64a6d1b98856318:
> 
>    Merge tag 'pull-tcg-20230626' of https://gitlab.com/rth7680/qemu 
> <https://gitlab.com/rth7680/qemu> into staging (2023-06-26 17:40:38 +0200)
> 
> are available in the Git repository at:
> 
> https://gitlab.com/marcandre.lureau/qemu.git 
> <https://gitlab.com/marcandre.lureau/qemu.git> tags/ui-pull-request
> 
> for you to fetch changes up to de1f8ce0abb8c43d1e6a00c31c6d24dfe0505b92:

That was enough, thanks.

Applied.  Please update https://wiki.qemu.org/ChangeLog/8.1 as appropriate.


r~



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible
  2023-06-27 13:02 ` [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible marcandre.lureau
@ 2023-06-29  7:40   ` Richard Henderson
  2023-06-29  7:45     ` Richard Henderson
  2023-06-29  8:35     ` Mark Cave-Ayland
  0 siblings, 2 replies; 46+ messages in thread
From: Richard Henderson @ 2023-06-29  7:40 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: Gerd Hoffmann

On 6/27/23 15:02, marcandre.lureau@redhat.com wrote:
>   static void dbus_update_gl_cb(GObject *source_object,
> -                           GAsyncResult *res,
> -                           gpointer user_data)
> +                              GAsyncResult *res,
> +                              gpointer user_data)
>   {
>       g_autoptr(GError) err = NULL;
>       DBusDisplayListener *ddl = user_data;
> +    bool success;
> +
> +#ifdef CONFIG_GBM
> +    success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
> +        ddl->proxy, res, &err);
> +#endif
> +
> +#ifdef WIN32
> +    success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
> +        ddl->d3d11_proxy, res, &err);
> +    d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
> +#endif
>   
> -    if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy,
> -                                                               res, &err)) {
> +    if (!success) {
>           error_report("Failed to call update: %s", err->message);
>       }

With neither CONFIG_GBM nor WIN32, success is not set:

../alt/ui/dbus-listener.c:199:10: error: variable 'success' is uninitialized when used 
here [-Werror,-Wuninitialized]
     if (!success) {
          ^~~~~~~


r~


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible
  2023-06-29  7:40   ` Richard Henderson
@ 2023-06-29  7:45     ` Richard Henderson
  2023-06-29  8:35     ` Mark Cave-Ayland
  1 sibling, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2023-06-29  7:45 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: Gerd Hoffmann

On 6/29/23 09:40, Richard Henderson wrote:
> On 6/27/23 15:02, marcandre.lureau@redhat.com wrote:
>>   static void dbus_update_gl_cb(GObject *source_object,
>> -                           GAsyncResult *res,
>> -                           gpointer user_data)
>> +                              GAsyncResult *res,
>> +                              gpointer user_data)
>>   {
>>       g_autoptr(GError) err = NULL;
>>       DBusDisplayListener *ddl = user_data;
>> +    bool success;
>> +
>> +#ifdef CONFIG_GBM
>> +    success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
>> +        ddl->proxy, res, &err);
>> +#endif
>> +
>> +#ifdef WIN32
>> +    success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
>> +        ddl->d3d11_proxy, res, &err);
>> +    d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
>> +#endif
>> -    if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy,
>> -                                                               res, &err)) {
>> +    if (!success) {
>>           error_report("Failed to call update: %s", err->message);
>>       }
> 
> With neither CONFIG_GBM nor WIN32, success is not set:
> 
> ../alt/ui/dbus-listener.c:199:10: error: variable 'success' is uninitialized when used 
> here [-Werror,-Wuninitialized]
>      if (!success) {
>           ^~~~~~~

Bah.  Working around that, the whole function isn't used under these same conditions:

../alt/ui/dbus-listener.c:180:13: error: unused function 'dbus_update_gl_cb' 
[-Werror,-Wunused-function]
static void dbus_update_gl_cb(GObject *source_object, GAsyncResult *res,
             ^
1 error generated.

Definitely some cleanup to the ifdefs required...


r~



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible
  2023-06-29  7:40   ` Richard Henderson
  2023-06-29  7:45     ` Richard Henderson
@ 2023-06-29  8:35     ` Mark Cave-Ayland
  1 sibling, 0 replies; 46+ messages in thread
From: Mark Cave-Ayland @ 2023-06-29  8:35 UTC (permalink / raw)
  To: Richard Henderson, marcandre.lureau, qemu-devel; +Cc: Gerd Hoffmann

On 29/06/2023 08:40, Richard Henderson wrote:

> On 6/27/23 15:02, marcandre.lureau@redhat.com wrote:
>>   static void dbus_update_gl_cb(GObject *source_object,
>> -                           GAsyncResult *res,
>> -                           gpointer user_data)
>> +                              GAsyncResult *res,
>> +                              gpointer user_data)
>>   {
>>       g_autoptr(GError) err = NULL;
>>       DBusDisplayListener *ddl = user_data;
>> +    bool success;
>> +
>> +#ifdef CONFIG_GBM
>> +    success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
>> +        ddl->proxy, res, &err);
>> +#endif
>> +
>> +#ifdef WIN32
>> +    success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
>> +        ddl->d3d11_proxy, res, &err);
>> +    d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
>> +#endif
>> -    if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy,
>> -                                                               res, &err)) {
>> +    if (!success) {
>>           error_report("Failed to call update: %s", err->message);
>>       }
> 
> With neither CONFIG_GBM nor WIN32, success is not set:
> 
> ../alt/ui/dbus-listener.c:199:10: error: variable 'success' is uninitialized when 
> used here [-Werror,-Wuninitialized]
>      if (!success) {
>           ^~~~~~~

I'm seeing something similar to this on my builds of git master this morning:

cc -m64 -mcx16 -Ilibcommon.fa.p -Iui -I../ui -I/usr/include/pixman-1 
-I/usr/include/libpng16 -I/usr/include/spice-server -I/usr/include/spice-1 
-I/usr/include/p11-kit-1 -I/usr/include/SDL2 -I/usr/include/libmount 
-I/usr/include/blkid -I/usr/include/glib-2.0 
-I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/gio-unix-2.0 
-I/usr/include/slirp -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 
-I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 
-I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/cairo 
-I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/harfbuzz 
-I/usr/include/atk-1.0 -I/usr/include/uuid -I/usr/include/freetype2 
-I/usr/include/gdk-pixbuf-2.0 -I/usr/include/vte-2.91 -I/usr/include/cacard 
-I/usr/include/nss -I/usr/include/nspr -I/usr/include/PCSC -I/usr/include/libusb-1.0 
-fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O0 -g 
-fstack-protector-strong -Wundef -Wwrite-strings -Wmissing-prototypes 
-Wstrict-prototypes -Wredundant-decls -Wold-style-declaration -Wold-style-definition 
-Wtype-limits -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers 
-Wempty-body -Wnested-externs -Wendif-labels -Wexpansion-to-defined 
-Wimplicit-fallthrough=2 -Wmissing-format-attribute -Wno-missing-include-dirs 
-Wno-shift-negative-value -Wno-psabi -isystem 
/home/build/src/qemu/git/qemu/linux-headers -isystem linux-headers -iquote . -iquote 
/home/build/src/qemu/git/qemu -iquote /home/build/src/qemu/git/qemu/include -iquote 
/home/build/src/qemu/git/qemu/host/include/x86_64 -iquote 
/home/build/src/qemu/git/qemu/host/include/generic -iquote 
/home/build/src/qemu/git/qemu/tcg/i386 -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 
-D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fPIE -D_DEFAULT_SOURCE 
-D_XOPEN_SOURCE=600 -DNCURSES_WIDECHAR=1 -D_REENTRANT -DSTRUCT_IOVEC_DEFINED -MD -MQ 
libcommon.fa.p/ui_dbus-listener.c.o -MF libcommon.fa.p/ui_dbus-listener.c.o.d -o 
libcommon.fa.p/ui_dbus-listener.c.o -c ../ui/dbus-listener.c
../ui/dbus-listener.c: In function ‘dbus_call_update_gl’:
../ui/dbus-listener.c:210:26: error: unused variable ‘ddl’ [-Werror=unused-variable]
   210 |     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
       |                          ^~~
At top level:
../ui/dbus-listener.c:180:13: error: ‘dbus_update_gl_cb’ defined but not used 
[-Werror=unused-function]
   180 | static void dbus_update_gl_cb(GObject *source_object,
       |             ^~~~~~~~~~~~~~~~~
../ui/dbus-listener.c: In function ‘dbus_update_gl_cb’:
../ui/dbus-listener.c:199:9: error: ‘success’ is used uninitialized in this function 
[-Werror=uninitialized]
   199 |     if (!success) {
       |         ^~~~~~~~
cc1: all warnings being treated as errors
ninja: build stopped: subcommand failed.


ATB,

Mark.



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 17/33] ui/dbus: win32 support
  2023-06-27 13:02 ` [PULL 17/33] ui/dbus: win32 support marcandre.lureau
@ 2023-06-29 17:55   ` Bernhard Beschow
  2023-06-30 21:41     ` Marc-André Lureau
  0 siblings, 1 reply; 46+ messages in thread
From: Bernhard Beschow @ 2023-06-29 17:55 UTC (permalink / raw)
  To: qemu-devel, marcandre.lureau
  Cc: richard.henderson, Marc-André Lureau, Gerd Hoffmann,
	Paolo Bonzini, Daniel P. Berrangé,
	Thomas Huth, Philippe Mathieu-Daudé



Am 27. Juni 2023 13:02:14 UTC schrieb marcandre.lureau@redhat.com:
>From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
>D-Bus doesn't support fd-passing on Windows (AF_UNIX doesn't have
>SCM_RIGHTS yet, but there are other means to share objects. I have
>proposed various solutions upstream, but none seem fitting enough atm).
>
>To make the "-display dbus" work on Windows, implement an alternative
>D-Bus interface where all the 'h' (FDs) arguments are replaced with
>'ay' (WSASocketW data), and sockets are passed to the other end via
>WSADuplicateSocket().
>
>Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>Message-Id: <20230606115658.677673-6-marcandre.lureau@redhat.com>
>---
> meson.build          |  4 +--
> ui/dbus.h            |  6 +++++
> audio/dbusaudio.c    | 44 +++++++++++++++++++++++++++------
> ui/dbus-chardev.c    | 22 +++++++++++++----
> ui/dbus-console.c    | 59 ++++++++++++++++++++++++++++++++++++++------
> ui/dbus-display1.xml | 28 +++++++++++++++++++++
> ui/meson.build       |  9 ++++++-
> 7 files changed, 149 insertions(+), 23 deletions(-)
>
>diff --git a/meson.build b/meson.build
>index b409788832..9a1ce43471 100644
>--- a/meson.build
>+++ b/meson.build
>@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
>   gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support control flow integrity'
> endif
> 
>+xml_pp = find_program('scripts/xml-preprocess.py')
>+
> lttng = not_found
> if 'ust' in get_option('trace_backends')
>   lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
>@@ -1985,8 +1987,6 @@ dbus_display = get_option('dbus_display') \
>            error_message: '-display dbus requires glib>=2.64') \
>   .require(gdbus_codegen.found(),
>            error_message: gdbus_codegen_error.format('-display dbus')) \
>-  .require(targetos != 'windows',
>-           error_message: '-display dbus is not available on Windows') \
>   .allowed()
> 
> have_virtfs = get_option('virtfs') \
>diff --git a/ui/dbus.h b/ui/dbus.h
>index 9c149e7b41..1e8c24a48e 100644
>--- a/ui/dbus.h
>+++ b/ui/dbus.h
>@@ -62,6 +62,12 @@ struct DBusDisplay {
>     Notifier notifier;
> };
> 
>+#ifdef WIN32
>+bool
>+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
>+                         GVariant *arg_listener, int *socket);
>+#endif
>+
> #define TYPE_DBUS_DISPLAY "dbus-display"
> OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
> 
>diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
>index de59467d9e..7a11fbfb42 100644
>--- a/audio/dbusaudio.c
>+++ b/audio/dbusaudio.c
>@@ -33,6 +33,7 @@
> #include <gio/gunixfdlist.h>
> #endif
> 
>+#include "ui/dbus.h"

This patch causes below compile error since pixman.h isn't found. It seems as if the pixman include path is missing. Since pixman.h is found elsewhere in the same build I suspect that the DBUS audio module now needs a pixman dependency -- which sounds a little bit weired.

FAILED: libaudio-dbus.a.p/audio_dbusaudio.c.o 
cc -m64 -mcx16 -Ilibaudio-dbus.a.p -I. -I../src -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O0 -g -fstack-protector-strong -Wundef -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wold-style-declaration -Wold-style-definition -Wtype-limits -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wempty-body -Wnested-externs -Wendif-labels -Wexpansion-to-defined -Wimplicit-fallthrough=2 -Wmissing-format-attribute -Wno-missing-include-dirs -Wno-shift-negative-value -Wno-psabi -isystem qemu/src/linux-headers -isystem linux-headers -iquote . -iquote qemu/src -iquote qemu/src/include -iquote qemu/src/host/include/x86_64 -iquote qemu/src/host/include/generic -iquote qemu/src/tcg/i386 -Wno-unused-function -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -fPIC -DBUILD_DSO -MD -MQ libaudio-dbus.a.p/audio_dbusaudio.c.o -MF libaudio-dbus.a.p/audio_dbusaudio.c.o.d -o libaudio-dbus.a.p/audio_dbusaudio.c.o -c ../src/audio/dbusaudio.c
In file included from qemu/src/include/ui/console.h:4,
                 from qemu/src/ui/dbus.h:31,
                 from ../src/audio/dbusaudio.c:36:
qemu/src/include/ui/qemu-pixman.h:12:10: fatal error: pixman.h: No such file or directory
   12 | #include <pixman.h>
      |          ^~~~~~~~~~

Best regards,
Bernhard

> #include "ui/dbus-display1.h"
> 
> #define AUDIO_CAP "dbus"
>@@ -422,7 +423,6 @@ dbus_audio_fini(void *opaque)
>     g_free(da);
> }
> 
>-#ifdef G_OS_UNIX
> static void
> listener_out_vanished_cb(GDBusConnection *connection,
>                          gboolean remote_peer_vanished,
>@@ -448,7 +448,9 @@ listener_in_vanished_cb(GDBusConnection *connection,
> static gboolean
> dbus_audio_register_listener(AudioState *s,
>                              GDBusMethodInvocation *invocation,
>+#ifdef G_OS_UNIX
>                              GUnixFDList *fd_list,
>+#endif
>                              GVariant *arg_listener,
>                              bool out)
> {
>@@ -475,6 +477,11 @@ dbus_audio_register_listener(AudioState *s,
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
> 
>+#ifdef G_OS_WIN32
>+    if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
>+        return DBUS_METHOD_INVOCATION_HANDLED;
>+    }
>+#else
>     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
>     if (err) {
>         g_dbus_method_invocation_return_error(invocation,
>@@ -484,6 +491,7 @@ dbus_audio_register_listener(AudioState *s,
>                                               err->message);
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
>+#endif
> 
>     socket = g_socket_new_from_fd(fd, &err);
>     if (err) {
>@@ -492,15 +500,28 @@ dbus_audio_register_listener(AudioState *s,
>                                               DBUS_DISPLAY_ERROR_FAILED,
>                                               "Couldn't make a socket: %s",
>                                               err->message);
>+#ifdef G_OS_WIN32
>+        closesocket(fd);
>+#else
>+        close(fd);
>+#endif
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
>     socket_conn = g_socket_connection_factory_create_connection(socket);
>     if (out) {
>         qemu_dbus_display1_audio_complete_register_out_listener(
>-            da->iface, invocation, NULL);
>+            da->iface, invocation
>+#ifdef G_OS_UNIX
>+            , NULL
>+#endif
>+            );
>     } else {
>         qemu_dbus_display1_audio_complete_register_in_listener(
>-            da->iface, invocation, NULL);
>+            da->iface, invocation
>+#ifdef G_OS_UNIX
>+            , NULL
>+#endif
>+            );
>     }
> 
>     listener_conn =
>@@ -578,24 +599,33 @@ dbus_audio_register_listener(AudioState *s,
> static gboolean
> dbus_audio_register_out_listener(AudioState *s,
>                                  GDBusMethodInvocation *invocation,
>+#ifdef G_OS_UNIX
>                                  GUnixFDList *fd_list,
>+#endif
>                                  GVariant *arg_listener)
> {
>     return dbus_audio_register_listener(s, invocation,
>-                                        fd_list, arg_listener, true);
>+#ifdef G_OS_UNIX
>+                                        fd_list,
>+#endif
>+                                        arg_listener, true);
> 
> }
> 
> static gboolean
> dbus_audio_register_in_listener(AudioState *s,
>                                 GDBusMethodInvocation *invocation,
>+#ifdef G_OS_UNIX
>                                 GUnixFDList *fd_list,
>+#endif
>                                 GVariant *arg_listener)
> {
>     return dbus_audio_register_listener(s, invocation,
>-                                        fd_list, arg_listener, false);
>-}
>+#ifdef G_OS_UNIX
>+                                        fd_list,
> #endif
>+                                        arg_listener, false);
>+}
> 
> static void
> dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
>@@ -610,14 +640,12 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
> 
>     da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
>     da->iface = qemu_dbus_display1_audio_skeleton_new();
>-#ifdef G_OS_UNIX
>     g_object_connect(da->iface,
>                      "swapped-signal::handle-register-in-listener",
>                      dbus_audio_register_in_listener, s,
>                      "swapped-signal::handle-register-out-listener",
>                      dbus_audio_register_out_listener, s,
>                      NULL);
>-#endif
> 
>     g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
>                                          G_DBUS_INTERFACE_SKELETON(da->iface));
>diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c
>index 7154d81a9a..1d3a7122a1 100644
>--- a/ui/dbus-chardev.c
>+++ b/ui/dbus-chardev.c
>@@ -110,18 +110,24 @@ dbus_chardev_init(DBusDisplay *dpy)
>                          dbus_display_chardev_foreach, dpy);
> }
> 
>-#ifdef G_OS_UNIX
> static gboolean
> dbus_chr_register(
>     DBusChardev *dc,
>     GDBusMethodInvocation *invocation,
>+#ifdef G_OS_UNIX
>     GUnixFDList *fd_list,
>+#endif
>     GVariant *arg_stream,
>     QemuDBusDisplay1Chardev *object)
> {
>     g_autoptr(GError) err = NULL;
>     int fd;
> 
>+#ifdef G_OS_WIN32
>+    if (!dbus_win32_import_socket(invocation, arg_stream, &fd)) {
>+        return DBUS_METHOD_INVOCATION_HANDLED;
>+    }
>+#else
>     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_stream), &err);
>     if (err) {
>         g_dbus_method_invocation_return_error(
>@@ -131,13 +137,18 @@ dbus_chr_register(
>             "Couldn't get peer FD: %s", err->message);
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
>+#endif
> 
>     if (qemu_chr_add_client(CHARDEV(dc), fd) < 0) {
>         g_dbus_method_invocation_return_error(invocation,
>                                               DBUS_DISPLAY_ERROR,
>                                               DBUS_DISPLAY_ERROR_FAILED,
>                                               "Couldn't register FD!");
>+#ifdef G_OS_WIN32
>+        closesocket(fd);
>+#else
>         close(fd);
>+#endif
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
> 
>@@ -145,10 +156,13 @@ dbus_chr_register(
>                  "owner", g_dbus_method_invocation_get_sender(invocation),
>                  NULL);
> 
>-    qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
>+    qemu_dbus_display1_chardev_complete_register(object, invocation
>+#ifndef G_OS_WIN32
>+                                                 , NULL
>+#endif
>+        );
>     return DBUS_METHOD_INVOCATION_HANDLED;
> }
>-#endif
> 
> static gboolean
> dbus_chr_send_break(
>@@ -179,10 +193,8 @@ dbus_chr_open(Chardev *chr, ChardevBackend *backend,
>     dc->iface = qemu_dbus_display1_chardev_skeleton_new();
>     g_object_set(dc->iface, "name", backend->u.dbus.data->name, NULL);
>     g_object_connect(dc->iface,
>-#ifdef G_OS_UNIX
>                      "swapped-signal::handle-register",
>                      dbus_chr_register, dc,
>-#endif
>                      "swapped-signal::handle-send-break",
>                      dbus_chr_send_break, dc,
>                      NULL);
>diff --git a/ui/dbus-console.c b/ui/dbus-console.c
>index d5f6c93637..4a1c1fb55e 100644
>--- a/ui/dbus-console.c
>+++ b/ui/dbus-console.c
>@@ -165,7 +165,6 @@ dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
>     gobject_class->dispose = dbus_display_console_dispose;
> }
> 
>-#ifdef G_OS_UNIX
> static void
> listener_vanished_cb(DBusDisplayListener *listener)
> {
>@@ -177,7 +176,6 @@ listener_vanished_cb(DBusDisplayListener *listener)
>     g_hash_table_remove(ddc->listeners, name);
>     qkbd_state_lift_all_keys(ddc->kbd);
> }
>-#endif
> 
> static gboolean
> dbus_console_set_ui_info(DBusDisplayConsole *ddc,
>@@ -211,11 +209,47 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
>     return DBUS_METHOD_INVOCATION_HANDLED;
> }
> 
>-#ifdef G_OS_UNIX
>+#ifdef G_OS_WIN32
>+bool
>+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
>+                         GVariant *arg_listener, int *socket)
>+{
>+    gsize n;
>+    WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
>+
>+    if (!info || n != sizeof(*info)) {
>+        g_dbus_method_invocation_return_error(
>+            invocation,
>+            DBUS_DISPLAY_ERROR,
>+            DBUS_DISPLAY_ERROR_FAILED,
>+            "Failed to get socket infos");
>+        return false;
>+    }
>+
>+    *socket = WSASocketW(FROM_PROTOCOL_INFO,
>+                         FROM_PROTOCOL_INFO,
>+                         FROM_PROTOCOL_INFO,
>+                         info, 0, 0);
>+    if (*socket == INVALID_SOCKET) {
>+        g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
>+        g_dbus_method_invocation_return_error(
>+            invocation,
>+            DBUS_DISPLAY_ERROR,
>+            DBUS_DISPLAY_ERROR_FAILED,
>+            "Couldn't create socket: %s", emsg);
>+        return false;
>+    }
>+
>+    return true;
>+}
>+#endif
>+
> static gboolean
> dbus_console_register_listener(DBusDisplayConsole *ddc,
>                                GDBusMethodInvocation *invocation,
>+#ifdef G_OS_UNIX
>                                GUnixFDList *fd_list,
>+#endif
>                                GVariant *arg_listener)
> {
>     const char *sender = g_dbus_method_invocation_get_sender(invocation);
>@@ -237,6 +271,11 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
> 
>+#ifdef G_OS_WIN32
>+    if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
>+        return DBUS_METHOD_INVOCATION_HANDLED;
>+    }
>+#else
>     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
>     if (err) {
>         g_dbus_method_invocation_return_error(
>@@ -246,6 +285,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
>             "Couldn't get peer fd: %s", err->message);
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
>+#endif
> 
>     socket = g_socket_new_from_fd(fd, &err);
>     if (err) {
>@@ -254,13 +294,21 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
>             DBUS_DISPLAY_ERROR,
>             DBUS_DISPLAY_ERROR_FAILED,
>             "Couldn't make a socket: %s", err->message);
>+#ifdef G_OS_WIN32
>+        closesocket(fd);
>+#else
>         close(fd);
>+#endif
>         return DBUS_METHOD_INVOCATION_HANDLED;
>     }
>     socket_conn = g_socket_connection_factory_create_connection(socket);
> 
>     qemu_dbus_display1_console_complete_register_listener(
>-        ddc->iface, invocation, NULL);
>+        ddc->iface, invocation
>+#ifdef G_OS_UNIX
>+        , NULL
>+#endif
>+    );
> 
>     listener_conn = g_dbus_connection_new_sync(
>         G_IO_STREAM(socket_conn),
>@@ -287,7 +335,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
>     trace_dbus_registered_listener(sender);
>     return DBUS_METHOD_INVOCATION_HANDLED;
> }
>-#endif
> 
> static gboolean
> dbus_kbd_press(DBusDisplayConsole *ddc,
>@@ -516,10 +563,8 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
>         "device-address", device_addr,
>         NULL);
>     g_object_connect(ddc->iface,
>-#ifdef G_OS_UNIX
>         "swapped-signal::handle-register-listener",
>         dbus_console_register_listener, ddc,
>-#endif
>         "swapped-signal::handle-set-uiinfo",
>         dbus_console_set_ui_info, ddc,
>         NULL);
>diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
>index cc0c9b68bf..cd596f774e 100644
>--- a/ui/dbus-display1.xml
>+++ b/ui/dbus-display1.xml
>@@ -57,7 +57,13 @@
>         :dbus:iface:`org.qemu.Display1.Listener` interface.
>     -->
>     <method name="RegisterListener">
>+      <?if $(env.TARGETOS) == windows?>
>+      <arg type="ay" name="listener" direction="in">
>+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
>+      </arg>
>+      <?else?>
>       <arg type="h" name="listener" direction="in"/>
>+      <?endif?>
>     </method>
> 
>     <!--
>@@ -334,6 +340,9 @@
>       </arg>
>     </method>
> 
>+    <?if $(env.TARGETOS) == windows?>
>+    <!-- Add shared memory/texture support -->
>+    <?else?>
>     <!--
>         ScanoutDMABUF:
>         @dmabuf: the DMABUF file descriptor.
>@@ -372,6 +381,7 @@
>       <arg type="i" name="width" direction="in"/>
>       <arg type="i" name="height" direction="in"/>
>     </method>
>+    <?endif?>
> 
>     <!--
>         Disable:
>@@ -532,7 +542,13 @@
>         :dbus:iface:`org.qemu.Display1.AudioOutListener` interface.
>     -->
>     <method name="RegisterOutListener">
>+      <?if $(env.TARGETOS) == windows?>
>+      <arg type="ay" name="listener" direction="in">
>+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
>+      </arg>
>+      <?else?>
>       <arg type="h" name="listener" direction="in"/>
>+      <?endif?>
>     </method>
> 
>     <!--
>@@ -547,7 +563,13 @@
>         :dbus:iface:`org.qemu.Display1.AudioInListener` interface.
>     -->
>     <method name="RegisterInListener">
>+      <?if $(env.TARGETOS) == windows?>
>+      <arg type="ay" name="listener" direction="in">
>+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
>+      </arg>
>+      <?else?>
>       <arg type="h" name="listener" direction="in"/>
>+      <?endif?>
>     </method>
>   </interface>
> 
>@@ -760,7 +782,13 @@
>         The current handler, if any, will be replaced.
>     -->
>     <method name="Register">
>+      <?if $(env.TARGETOS) == windows?>
>+      <arg type="ay" name="listener" direction="in">
>+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
>+      </arg>
>+      <?else?>
>       <arg type="h" name="stream" direction="in"/>
>+      <?endif?>
>     </method>
> 
>     <!--
>diff --git a/ui/meson.build b/ui/meson.build
>index a5506ac8ad..d84650676d 100644
>--- a/ui/meson.build
>+++ b/ui/meson.build
>@@ -74,9 +74,16 @@ endif
> 
> if dbus_display
>   dbus_ss = ss.source_set()
>+  env = environment()
>+  env.set('TARGETOS', targetos)
>+  xml = custom_target('dbus-display preprocess',
>+                      input: 'dbus-display1.xml',
>+                      output: 'dbus-display1.xml',
>+                      env: env,
>+                      command: [xml_pp, '@INPUT@', '@OUTPUT@'])
>   dbus_display1 = custom_target('dbus-display gdbus-codegen',
>                                 output: ['dbus-display1.h', 'dbus-display1.c'],
>-                                input: files('dbus-display1.xml'),
>+                                input: xml,
>                                 command: [gdbus_codegen, '@INPUT@',
>                                           '--glib-min-required', '2.64',
>                                           '--output-directory', meson.current_build_dir(),


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 17/33] ui/dbus: win32 support
  2023-06-29 17:55   ` Bernhard Beschow
@ 2023-06-30 21:41     ` Marc-André Lureau
  2023-06-30 23:51       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 46+ messages in thread
From: Marc-André Lureau @ 2023-06-30 21:41 UTC (permalink / raw)
  To: Bernhard Beschow
  Cc: qemu-devel, richard.henderson, Gerd Hoffmann, Paolo Bonzini,
	Daniel P. Berrangé, Thomas Huth, Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 5190 bytes --]

Hi

On Thu, Jun 29, 2023 at 7:55 PM Bernhard Beschow <shentey@gmail.com> wrote:

>
>
> Am 27. Juni 2023 13:02:14 UTC schrieb marcandre.lureau@redhat.com:
> >From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> >D-Bus doesn't support fd-passing on Windows (AF_UNIX doesn't have
> >SCM_RIGHTS yet, but there are other means to share objects. I have
> >proposed various solutions upstream, but none seem fitting enough atm).
> >
> >To make the "-display dbus" work on Windows, implement an alternative
> >D-Bus interface where all the 'h' (FDs) arguments are replaced with
> >'ay' (WSASocketW data), and sockets are passed to the other end via
> >WSADuplicateSocket().
> >
> >Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >Message-Id: <20230606115658.677673-6-marcandre.lureau@redhat.com>
> >---
> > meson.build          |  4 +--
> > ui/dbus.h            |  6 +++++
> > audio/dbusaudio.c    | 44 +++++++++++++++++++++++++++------
> > ui/dbus-chardev.c    | 22 +++++++++++++----
> > ui/dbus-console.c    | 59 ++++++++++++++++++++++++++++++++++++++------
> > ui/dbus-display1.xml | 28 +++++++++++++++++++++
> > ui/meson.build       |  9 ++++++-
> > 7 files changed, 149 insertions(+), 23 deletions(-)
> >
> >diff --git a/meson.build b/meson.build
> >index b409788832..9a1ce43471 100644
> >--- a/meson.build
> >+++ b/meson.build
> >@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
> >   gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support
> control flow integrity'
> > endif
> >
> >+xml_pp = find_program('scripts/xml-preprocess.py')
> >+
> > lttng = not_found
> > if 'ust' in get_option('trace_backends')
> >   lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
> >@@ -1985,8 +1987,6 @@ dbus_display = get_option('dbus_display') \
> >            error_message: '-display dbus requires glib>=2.64') \
> >   .require(gdbus_codegen.found(),
> >            error_message: gdbus_codegen_error.format('-display dbus')) \
> >-  .require(targetos != 'windows',
> >-           error_message: '-display dbus is not available on Windows') \
> >   .allowed()
> >
> > have_virtfs = get_option('virtfs') \
> >diff --git a/ui/dbus.h b/ui/dbus.h
> >index 9c149e7b41..1e8c24a48e 100644
> >--- a/ui/dbus.h
> >+++ b/ui/dbus.h
> >@@ -62,6 +62,12 @@ struct DBusDisplay {
> >     Notifier notifier;
> > };
> >
> >+#ifdef WIN32
> >+bool
> >+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
> >+                         GVariant *arg_listener, int *socket);
> >+#endif
> >+
> > #define TYPE_DBUS_DISPLAY "dbus-display"
> > OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
> >
> >diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
> >index de59467d9e..7a11fbfb42 100644
> >--- a/audio/dbusaudio.c
> >+++ b/audio/dbusaudio.c
> >@@ -33,6 +33,7 @@
> > #include <gio/gunixfdlist.h>
> > #endif
> >
> >+#include "ui/dbus.h"
>
> This patch causes below compile error since pixman.h isn't found. It seems
> as if the pixman include path is missing. Since pixman.h is found elsewhere
> in the same build I suspect that the DBUS audio module now needs a pixman
> dependency -- which sounds a little bit weired.
>
> FAILED: libaudio-dbus.a.p/audio_dbusaudio.c.o
> cc -m64 -mcx16 -Ilibaudio-dbus.a.p -I. -I../src -Iqapi -Itrace -Iui
> -Iui/shader -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
> -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid
> -I/usr/include/gio-unix-2.0 -fdiagnostics-color=auto -Wall -Winvalid-pch
> -Werror -std=gnu11 -O0 -g -fstack-protector-strong -Wundef -Wwrite-strings
> -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls
> -Wold-style-declaration -Wold-style-definition -Wtype-limits
> -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers
> -Wempty-body -Wnested-externs -Wendif-labels -Wexpansion-to-defined
> -Wimplicit-fallthrough=2 -Wmissing-format-attribute
> -Wno-missing-include-dirs -Wno-shift-negative-value -Wno-psabi -isystem
> qemu/src/linux-headers -isystem linux-headers -iquote . -iquote qemu/src
> -iquote qemu/src/include -iquote qemu/src/host/include/x86_64 -iquote
> qemu/src/host/include/generic -iquote qemu/src/tcg/i386
> -Wno-unused-function -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
> -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -march=x86-64
> -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2
> -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection
> -fPIC -DBUILD_DSO -MD -MQ libaudio-dbus.a.p/audio_dbusaudio.c.o -MF
> libaudio-dbus.a.p/audio_dbusaudio.c.o.d -o
> libaudio-dbus.a.p/audio_dbusaudio.c.o -c ../src/audio/dbusaudio.c
> In file included from qemu/src/include/ui/console.h:4,
>                  from qemu/src/ui/dbus.h:31,
>                  from ../src/audio/dbusaudio.c:36:
> qemu/src/include/ui/qemu-pixman.h:12:10: fatal error: pixman.h: No such
> file or directory
>    12 | #include <pixman.h>
>       |          ^~~~~~~~~~
>
>
This is reported here:
https://gitlab.com/qemu-project/qemu/-/issues/1739

I am going to send the patch.

[-- Attachment #2: Type: text/html, Size: 6549 bytes --]

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 17/33] ui/dbus: win32 support
  2023-06-30 21:41     ` Marc-André Lureau
@ 2023-06-30 23:51       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 46+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-30 23:51 UTC (permalink / raw)
  To: Marc-André Lureau, Bernhard Beschow
  Cc: qemu-devel, richard.henderson, Gerd Hoffmann, Paolo Bonzini,
	Daniel P. Berrangé,
	Thomas Huth

On 30/6/23 23:41, Marc-André Lureau wrote:
> Hi
> 
> On Thu, Jun 29, 2023 at 7:55 PM Bernhard Beschow <shentey@gmail.com 
> <mailto:shentey@gmail.com>> wrote:
> 
> 
> 
>     Am 27. Juni 2023 13:02:14 UTC schrieb marcandre.lureau@redhat.com
>     <mailto:marcandre.lureau@redhat.com>:
>      >From: Marc-André Lureau <marcandre.lureau@redhat.com
>     <mailto:marcandre.lureau@redhat.com>>
>      >
>      >D-Bus doesn't support fd-passing on Windows (AF_UNIX doesn't have
>      >SCM_RIGHTS yet, but there are other means to share objects. I have
>      >proposed various solutions upstream, but none seem fitting enough
>     atm).
>      >
>      >To make the "-display dbus" work on Windows, implement an alternative
>      >D-Bus interface where all the 'h' (FDs) arguments are replaced with
>      >'ay' (WSASocketW data), and sockets are passed to the other end via
>      >WSADuplicateSocket().
>      >
>      >Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com
>     <mailto:marcandre.lureau@redhat.com>>
>      >Message-Id: <20230606115658.677673-6-marcandre.lureau@redhat.com
>     <mailto:20230606115658.677673-6-marcandre.lureau@redhat.com>>
>      >---
>      > meson.build          |  4 +--
>      > ui/dbus.h            |  6 +++++
>      > audio/dbusaudio.c    | 44 +++++++++++++++++++++++++++------
>      > ui/dbus-chardev.c    | 22 +++++++++++++----
>      > ui/dbus-console.c    | 59
>     ++++++++++++++++++++++++++++++++++++++------
>      > ui/dbus-display1.xml | 28 +++++++++++++++++++++
>      > ui/meson.build       |  9 ++++++-
>      > 7 files changed, 149 insertions(+), 23 deletions(-)
>      >
>      >diff --git a/meson.build b/meson.build
>      >index b409788832..9a1ce43471 100644
>      >--- a/meson.build
>      >+++ b/meson.build
>      >@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
>      >   gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not
>     support control flow integrity'
>      > endif
>      >
>      >+xml_pp = find_program('scripts/xml-preprocess.py')
>      >+
>      > lttng = not_found
>      > if 'ust' in get_option('trace_backends')
>      >   lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
>      >@@ -1985,8 +1987,6 @@ dbus_display = get_option('dbus_display') \
>      >            error_message: '-display dbus requires glib>=2.64') \
>      >   .require(gdbus_codegen.found(),
>      >            error_message: gdbus_codegen_error.format('-display
>     dbus')) \
>      >-  .require(targetos != 'windows',
>      >-           error_message: '-display dbus is not available on
>     Windows') \
>      >   .allowed()
>      >
>      > have_virtfs = get_option('virtfs') \
>      >diff --git a/ui/dbus.h b/ui/dbus.h
>      >index 9c149e7b41..1e8c24a48e 100644
>      >--- a/ui/dbus.h
>      >+++ b/ui/dbus.h
>      >@@ -62,6 +62,12 @@ struct DBusDisplay {
>      >     Notifier notifier;
>      > };
>      >
>      >+#ifdef WIN32
>      >+bool
>      >+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
>      >+                         GVariant *arg_listener, int *socket);
>      >+#endif
>      >+
>      > #define TYPE_DBUS_DISPLAY "dbus-display"
>      > OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
>      >
>      >diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
>      >index de59467d9e..7a11fbfb42 100644
>      >--- a/audio/dbusaudio.c
>      >+++ b/audio/dbusaudio.c
>      >@@ -33,6 +33,7 @@
>      > #include <gio/gunixfdlist.h>
>      > #endif
>      >
>      >+#include "ui/dbus.h"
> 
>     This patch causes below compile error since pixman.h isn't found. It
>     seems as if the pixman include path is missing. Since pixman.h is
>     found elsewhere in the same build I suspect that the DBUS audio
>     module now needs a pixman dependency -- which sounds a little bit
>     weired.
> 
>     FAILED: libaudio-dbus.a.p/audio_dbusaudio.c.o
>     cc -m64 -mcx16 -Ilibaudio-dbus.a.p -I. -I../src -Iqapi -Itrace -Iui
>     -Iui/shader -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
>     -I/usr/include/sysprof-4 -I/usr/include/libmount
>     -I/usr/include/blkid -I/usr/include/gio-unix-2.0
>     -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O0
>     -g -fstack-protector-strong -Wundef -Wwrite-strings
>     -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls
>     -Wold-style-declaration -Wold-style-definition -Wtype-limits
>     -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers
>     -Wempty-body -Wnested-externs -Wendif-labels -Wexpansion-to-defined
>     -Wimplicit-fallthrough=2 -Wmissing-format-attribute
>     -Wno-missing-include-dirs -Wno-shift-negative-value -Wno-psabi
>     -isystem qemu/src/linux-headers -isystem linux-headers -iquote .
>     -iquote qemu/src -iquote qemu/src/include -iquote
>     qemu/src/host/include/x86_64 -iquote qemu/src/host/include/generic
>     -iquote qemu/src/tcg/i386 -Wno-unused-function -pthread
>     -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
>     -fno-strict-aliasing -fno-common -fwrapv -march=x86-64
>     -mtune=generic -O2 -pipe -fno-plt -fexceptions
>     -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security
>     -fstack-clash-protection -fcf-protection -fPIC -DBUILD_DSO -MD -MQ
>     libaudio-dbus.a.p/audio_dbusaudio.c.o -MF
>     libaudio-dbus.a.p/audio_dbusaudio.c.o.d -o
>     libaudio-dbus.a.p/audio_dbusaudio.c.o -c ../src/audio/dbusaudio.c
>     In file included from qemu/src/include/ui/console.h:4,
>                       from qemu/src/ui/dbus.h:31,
>                       from ../src/audio/dbusaudio.c:36:
>     qemu/src/include/ui/qemu-pixman.h:12:10: fatal error: pixman.h: No
>     such file or directory
>         12 | #include <pixman.h>
>            |          ^~~~~~~~~~
> 
> 
> This is reported here:
> https://gitlab.com/qemu-project/qemu/-/issues/1739 
> <https://gitlab.com/qemu-project/qemu/-/issues/1739>
> 
> I am going to send the patch.

I just send a patch fixing this error, see:
https://lore.kernel.org/qemu-devel/20230630234839.14716-1-philmd@linaro.org/


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images
  2023-06-27 13:02 ` [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images marcandre.lureau
@ 2023-07-03 11:45   ` Alexander Bulekov
  2023-07-03 14:11   ` Peter Maydell
  1 sibling, 0 replies; 46+ messages in thread
From: Alexander Bulekov @ 2023-07-03 11:45 UTC (permalink / raw)
  To: marcandre.lureau
  Cc: qemu-devel, richard.henderson, Michael S. Tsirkin, Gerd Hoffmann

On 230627 1502, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Allocate pixman bits for scanouts with qemu_win32_map_alloc() so we can
> set a shareable handle on the associated display surface.
> 
> Note: when bits are provided to pixman_image_create_bits(), you must also give
> the rowstride (the argument is ignored when bits is NULL)
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Message-Id: <20230606115658.677673-11-marcandre.lureau@redhat.com>
> ---
>  include/hw/virtio/virtio-gpu.h |  3 +++
>  hw/display/virtio-gpu.c        | 46 +++++++++++++++++++++++++++++++---
>  2 files changed, 46 insertions(+), 3 deletions(-)
> 
> diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
> index 2e28507efe..7a5f8056ea 100644
> --- a/include/hw/virtio/virtio-gpu.h
> +++ b/include/hw/virtio/virtio-gpu.h
> @@ -48,6 +48,9 @@ struct virtio_gpu_simple_resource {
>      unsigned int iov_cnt;
>      uint32_t scanout_bitmask;
>      pixman_image_t *image;
> +#ifdef WIN32
> +    HANDLE handle;
> +#endif
>      uint64_t hostmem;
>  
>      uint64_t blob_size;
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 1f8a5b16c6..347e17d490 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -258,6 +258,16 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
>      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,
>                                            struct virtio_gpu_ctrl_command *cmd)
>  {
> @@ -304,12 +314,27 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
>  
>      res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
>      if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
> +        void *bits = NULL;
> +#ifdef WIN32
> +        bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
> +        if (!bits) {
> +            goto end;
> +        }
> +#endif
>          res->image = pixman_image_create_bits(pformat,
>                                                c2d.width,
>                                                c2d.height,
> -                                              NULL, 0);
> +                                              bits, res->hostmem / c2d.height);

Hello,
This may lead to FPE when c2d.height is 0.
https://gitlab.com/qemu-project/qemu/-/issues/1744
-Alex


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images
  2023-06-27 13:02 ` [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images marcandre.lureau
  2023-07-03 11:45   ` Alexander Bulekov
@ 2023-07-03 14:11   ` Peter Maydell
  1 sibling, 0 replies; 46+ messages in thread
From: Peter Maydell @ 2023-07-03 14:11 UTC (permalink / raw)
  To: marcandre.lureau
  Cc: qemu-devel, richard.henderson, Michael S. Tsirkin, Gerd Hoffmann

On Tue, 27 Jun 2023 at 14:07, <marcandre.lureau@redhat.com> wrote:
>
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Allocate pixman bits for scanouts with qemu_win32_map_alloc() so we can
> set a shareable handle on the associated display surface.
>
> Note: when bits are provided to pixman_image_create_bits(), you must also give
> the rowstride (the argument is ignored when bits is NULL)
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Message-Id: <20230606115658.677673-11-marcandre.lureau@redhat.com>

Hi; Coverity notes (CID 1516557) that this introduces
a possible division-by-zero (different from the one
Alex's fuzzer found):

> @@ -1252,15 +1281,23 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
>              g_free(res);
>              return -EINVAL;
>          }
> +
> +        res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
> +#ifdef WIN32
> +        bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
> +        if (!bits) {
> +            g_free(res);
> +            return -EINVAL;
> +        }
> +#endif
>          res->image = pixman_image_create_bits(pformat,
>                                                res->width, res->height,
> -                                              NULL, 0);
> +                                              bits, res->hostmem / res->height);

In this function we've just pulled res->height out of the
incoming migration stream, and we haven't done any sanity
checking on it. So it might be 0, in which case this division
will divide by zero and fall over.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2023-07-03 14:12 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-27 13:01 [PULL 00/33] UI patches marcandre.lureau
2023-06-27 13:01 ` [PULL 01/33] ui: return NULL when getting cursor without a console marcandre.lureau
2023-06-27 13:01 ` [PULL 02/33] egl: no need to lookup EGL functions manually marcandre.lureau
2023-06-27 13:02 ` [PULL 03/33] ui/sdl2: OpenGL window context marcandre.lureau
2023-06-27 13:02 ` [PULL 04/33] virtio-gpu: Optimize 2D resource data transfer marcandre.lureau
2023-06-27 15:04   ` Richard Henderson
2023-06-27 15:10     ` Marc-André Lureau
2023-06-28  9:22       ` Richard Henderson
2023-06-27 13:02 ` [PULL 05/33] chardev/char-win-stdio: Support VT sequences on Windows 11 host marcandre.lureau
2023-06-27 13:02 ` [PULL 06/33] ui/touch: Move event handling to a common helper marcandre.lureau
2023-06-27 13:02 ` [PULL 07/33] ui/dbus: Expose a touch device interface marcandre.lureau
2023-06-27 13:02 ` [PULL 08/33] virtio-gpu: Make non-gl display updates work again when blob=true marcandre.lureau
2023-06-27 13:02 ` [PULL 09/33] virtio-gpu-udmabuf: create udmabuf for blob even when iov_cnt == 1 marcandre.lureau
2023-06-27 13:02 ` [PULL 10/33] ui/gtk: set the area of the scanout texture correctly marcandre.lureau
2023-06-27 17:46   ` Michael Tokarev
2023-06-27 13:02 ` [PULL 11/33] virtio-gpu: OUT_OF_MEMORY if failing to create udmabuf marcandre.lureau
2023-06-27 13:02 ` [PULL 12/33] ui/gtk: making dmabuf NULL when it's released marcandre.lureau
2023-06-27 13:02 ` [PULL 13/33] ui/egl: export qemu_egl_get_error_string() marcandre.lureau
2023-06-27 13:02 ` [PULL 14/33] ui/egl: fix make_context_current() callback return value marcandre.lureau
2023-06-27 13:02 ` [PULL 15/33] ui/dbus: compile without gio/gunixfdlist.h marcandre.lureau
2023-06-27 13:02 ` [PULL 16/33] scripts: add a XML preprocessor script marcandre.lureau
2023-06-27 13:02 ` [PULL 17/33] ui/dbus: win32 support marcandre.lureau
2023-06-29 17:55   ` Bernhard Beschow
2023-06-30 21:41     ` Marc-André Lureau
2023-06-30 23:51       ` Philippe Mathieu-Daudé
2023-06-27 13:02 ` [PULL 18/33] qtest: add qtest_pid() marcandre.lureau
2023-06-27 13:02 ` [PULL 19/33] tests: make dbus-display-test work on win32 marcandre.lureau
2023-06-27 13:02 ` [PULL 20/33] ui/dbus: introduce "Interfaces" properties marcandre.lureau
2023-06-27 13:02 ` [PULL 21/33] console/win32: allocate shareable display surface marcandre.lureau
2023-06-27 13:02 ` [PULL 22/33] virtio-gpu/win32: allocate shareable 2d resources/images marcandre.lureau
2023-07-03 11:45   ` Alexander Bulekov
2023-07-03 14:11   ` Peter Maydell
2023-06-27 13:02 ` [PULL 23/33] ui/dbus: use shared memory when possible on win32 marcandre.lureau
2023-06-27 13:02 ` [PULL 24/33] ui: add egl-headless support " marcandre.lureau
2023-06-27 13:02 ` [PULL 25/33] ui/egl: default to GLES on windows marcandre.lureau
2023-06-27 13:02 ` [PULL 26/33] ui: add egl_fb_read_rect() marcandre.lureau
2023-06-27 13:02 ` [PULL 27/33] ui/dbus: add GL support on win32 marcandre.lureau
2023-06-27 13:02 ` [PULL 28/33] ui/dbus: add some GL traces marcandre.lureau
2023-06-27 13:02 ` [PULL 29/33] virtio-gpu-virgl: teach it to get the QEMU EGL display marcandre.lureau
2023-06-27 13:02 ` [PULL 30/33] ui/egl: query ANGLE d3d device marcandre.lureau
2023-06-27 13:02 ` [PULL 31/33] ui: add optional d3d texture pointer to scanout texture marcandre.lureau
2023-06-27 13:02 ` [PULL 32/33] virtio-gpu-virgl: use D3D11_SHARE_TEXTURE when available marcandre.lureau
2023-06-27 13:02 ` [PULL 33/33] ui/dbus: use shared D3D11 Texture2D when possible marcandre.lureau
2023-06-29  7:40   ` Richard Henderson
2023-06-29  7:45     ` Richard Henderson
2023-06-29  8:35     ` Mark Cave-Ayland

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.