2 * QEMU DBus display console
4 * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "qemu/osdep.h"
25 #include "qemu/error-report.h"
26 #include "qapi/error.h"
27 #include "sysemu/sysemu.h"
30 #include <gio/gunixfdlist.h>
38 #include "ui/shader.h"
39 #include "ui/egl-helpers.h"
40 #include "ui/egl-context.h"
41 #include "ui/qemu-pixman.h"
45 static void dbus_gfx_switch(DisplayChangeListener
*dcl
,
46 struct DisplaySurface
*new_surface
);
54 struct _DBusDisplayListener
{
58 DBusDisplayConsole
*console
;
59 GDBusConnection
*conn
;
61 QemuDBusDisplay1Listener
*proxy
;
64 /* Keep track of the damage region */
65 pixman_region32_t gl_damage
;
70 DisplayChangeListener dcl
;
72 enum share_kind ds_share
;
78 QemuDBusDisplay1ListenerWin32Map
*map_proxy
;
79 QemuDBusDisplay1ListenerWin32D3d11
*d3d11_proxy
;
81 ID3D11Texture2D
*d3d_texture
;
88 guint32 out_serial_to_discard
;
91 G_DEFINE_TYPE(DBusDisplayListener
, dbus_display_listener
, G_TYPE_OBJECT
)
93 static void dbus_gfx_update(DisplayChangeListener
*dcl
,
94 int x
, int y
, int w
, int h
);
96 static void ddl_discard_pending_messages(DBusDisplayListener
*ddl
)
98 ddl
->out_serial_to_discard
= g_dbus_connection_get_last_serial(
99 g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl
->proxy
)));
103 static void dbus_scanout_disable(DisplayChangeListener
*dcl
)
105 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
107 qemu_dbus_display1_listener_call_disable(
108 ddl
->proxy
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
112 static bool d3d_texture2d_share(ID3D11Texture2D
*d3d_texture
,
113 HANDLE
*handle
, Error
**errp
)
115 IDXGIResource1
*dxgiResource
= NULL
;
118 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
120 (void **)&dxgiResource
);
125 hr
= dxgiResource
->lpVtbl
->CreateSharedHandle(
128 DXGI_SHARED_RESOURCE_READ
| DXGI_SHARED_RESOURCE_WRITE
,
133 dxgiResource
->lpVtbl
->Release(dxgiResource
);
140 error_setg_win32(errp
, GetLastError(), "failed to create shared handle");
144 static bool d3d_texture2d_acquire0(ID3D11Texture2D
*d3d_texture
, Error
**errp
)
146 IDXGIKeyedMutex
*dxgiMutex
= NULL
;
149 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
150 &IID_IDXGIKeyedMutex
,
151 (void **)&dxgiMutex
);
156 hr
= dxgiMutex
->lpVtbl
->AcquireSync(dxgiMutex
, 0, INFINITE
);
158 dxgiMutex
->lpVtbl
->Release(dxgiMutex
);
165 error_setg_win32(errp
, GetLastError(), "failed to acquire texture mutex");
169 static bool d3d_texture2d_release0(ID3D11Texture2D
*d3d_texture
, Error
**errp
)
171 IDXGIKeyedMutex
*dxgiMutex
= NULL
;
174 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
175 &IID_IDXGIKeyedMutex
,
176 (void **)&dxgiMutex
);
181 hr
= dxgiMutex
->lpVtbl
->ReleaseSync(dxgiMutex
, 0);
183 dxgiMutex
->lpVtbl
->Release(dxgiMutex
);
190 error_setg_win32(errp
, GetLastError(), "failed to release texture mutex");
195 #if defined(CONFIG_GBM) || defined(WIN32)
196 static void dbus_update_gl_cb(GObject
*source_object
,
200 g_autoptr(GError
) err
= NULL
;
201 DBusDisplayListener
*ddl
= user_data
;
205 success
= qemu_dbus_display1_listener_call_update_dmabuf_finish(
206 ddl
->proxy
, res
, &err
);
210 success
= qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
211 ddl
->d3d11_proxy
, res
, &err
);
212 d3d_texture2d_acquire0(ddl
->d3d_texture
, &error_warn
);
216 error_report("Failed to call update: %s", err
->message
);
219 graphic_hw_gl_block(ddl
->dcl
.con
, false);
224 static void dbus_call_update_gl(DisplayChangeListener
*dcl
,
225 int x
, int y
, int w
, int h
)
227 #if defined(CONFIG_GBM) || defined(WIN32)
228 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
231 trace_dbus_update_gl(x
, y
, w
, h
);
235 graphic_hw_gl_block(ddl
->dcl
.con
, true);
236 qemu_dbus_display1_listener_call_update_dmabuf(ddl
->proxy
,
238 G_DBUS_CALL_FLAGS_NONE
,
239 DBUS_DEFAULT_TIMEOUT
, NULL
,
245 switch (ddl
->ds_share
) {
246 case SHARE_KIND_MAPPED
:
247 egl_fb_read_rect(ddl
->ds
, &ddl
->fb
, x
, y
, w
, h
);
248 dbus_gfx_update(dcl
, x
, y
, w
, h
);
250 case SHARE_KIND_D3DTEX
: {
252 assert(ddl
->d3d_texture
);
254 graphic_hw_gl_block(ddl
->dcl
.con
, true);
255 if (!d3d_texture2d_release0(ddl
->d3d_texture
, &err
)) {
256 error_report_err(err
);
259 qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
262 G_DBUS_CALL_FLAGS_NONE
,
263 DBUS_DEFAULT_TIMEOUT
, NULL
,
275 static void dbus_scanout_dmabuf(DisplayChangeListener
*dcl
,
278 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
279 g_autoptr(GError
) err
= NULL
;
280 g_autoptr(GUnixFDList
) fd_list
= NULL
;
282 uint32_t width
, height
, stride
, fourcc
;
286 fd
= qemu_dmabuf_get_fd(dmabuf
);
287 fd_list
= g_unix_fd_list_new();
288 if (g_unix_fd_list_append(fd_list
, fd
, &err
) != 0) {
289 error_report("Failed to setup dmabuf fdlist: %s", err
->message
);
293 ddl_discard_pending_messages(ddl
);
295 width
= qemu_dmabuf_get_width(dmabuf
);
296 height
= qemu_dmabuf_get_height(dmabuf
);
297 stride
= qemu_dmabuf_get_stride(dmabuf
);
298 fourcc
= qemu_dmabuf_get_fourcc(dmabuf
);
299 modifier
= qemu_dmabuf_get_modifier(dmabuf
);
300 y0_top
= qemu_dmabuf_get_y0_top(dmabuf
);
302 /* FIXME: add missing x/y/w/h support */
303 qemu_dbus_display1_listener_call_scanout_dmabuf(
304 ddl
->proxy
, g_variant_new_handle(0),
305 width
, height
, stride
, fourcc
, modifier
,
306 y0_top
, G_DBUS_CALL_FLAGS_NONE
,
307 -1, fd_list
, NULL
, NULL
, NULL
);
313 static bool dbus_scanout_map(DBusDisplayListener
*ddl
)
315 g_autoptr(GError
) err
= NULL
;
317 HANDLE target_handle
;
319 if (ddl
->ds_share
== SHARE_KIND_MAPPED
) {
323 if (!ddl
->can_share_map
|| !ddl
->ds
->handle
) {
327 success
= DuplicateHandle(
332 FILE_MAP_READ
| SECTION_QUERY
,
335 g_autofree
char *msg
= g_win32_error_message(GetLastError());
336 g_debug("Failed to DuplicateHandle: %s", msg
);
337 ddl
->can_share_map
= false;
341 ddl_discard_pending_messages(ddl
);
343 if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
345 GPOINTER_TO_UINT(target_handle
),
346 ddl
->ds
->handle_offset
,
347 surface_width(ddl
->ds
),
348 surface_height(ddl
->ds
),
349 surface_stride(ddl
->ds
),
350 surface_format(ddl
->ds
),
351 G_DBUS_CALL_FLAGS_NONE
,
352 DBUS_DEFAULT_TIMEOUT
,
355 g_debug("Failed to call ScanoutMap: %s", err
->message
);
356 ddl
->can_share_map
= false;
360 ddl
->ds_share
= SHARE_KIND_MAPPED
;
367 dbus_scanout_share_d3d_texture(
368 DBusDisplayListener
*ddl
,
369 ID3D11Texture2D
*tex
,
370 bool backing_y_0_top
,
371 uint32_t backing_width
,
372 uint32_t backing_height
,
373 uint32_t x
, uint32_t y
,
374 uint32_t w
, uint32_t h
)
378 HANDLE share_handle
, target_handle
;
380 if (!d3d_texture2d_release0(tex
, &err
)) {
381 error_report_err(err
);
385 if (!d3d_texture2d_share(tex
, &share_handle
, &err
)) {
386 error_report_err(err
);
390 success
= DuplicateHandle(
396 FALSE
, DUPLICATE_SAME_ACCESS
);
398 g_autofree
char *msg
= g_win32_error_message(GetLastError());
399 g_debug("Failed to DuplicateHandle: %s", msg
);
400 CloseHandle(share_handle
);
404 ddl_discard_pending_messages(ddl
);
406 qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
408 GPOINTER_TO_INT(target_handle
),
413 G_DBUS_CALL_FLAGS_NONE
,
417 CloseHandle(share_handle
);
419 if (!d3d_texture2d_acquire0(tex
, &err
)) {
420 error_report_err(err
);
424 ddl
->d3d_texture
= tex
;
425 ddl
->ds_share
= SHARE_KIND_D3DTEX
;
429 #endif /* CONFIG_OPENGL */
433 static void dbus_scanout_texture(DisplayChangeListener
*dcl
,
435 bool backing_y_0_top
,
436 uint32_t backing_width
,
437 uint32_t backing_height
,
438 uint32_t x
, uint32_t y
,
439 uint32_t w
, uint32_t h
,
442 trace_dbus_scanout_texture(tex_id
, backing_y_0_top
,
443 backing_width
, backing_height
, x
, y
, w
, h
);
445 g_autoptr(QemuDmaBuf
) dmabuf
= NULL
;
447 uint32_t stride
, fourcc
;
451 fd
= egl_get_fd_for_texture(tex_id
, (EGLint
*)&stride
, (EGLint
*)&fourcc
,
454 error_report("%s: failed to get fd for texture", __func__
);
457 dmabuf
= qemu_dmabuf_new(w
, h
, stride
, x
, y
, backing_width
,
458 backing_height
, fourcc
, modifier
, fd
,
459 false, backing_y_0_top
);
461 dbus_scanout_dmabuf(dcl
, dmabuf
);
462 qemu_dmabuf_close(dmabuf
);
466 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
468 /* there must be a matching gfx_switch before */
469 assert(surface_width(ddl
->ds
) == w
);
470 assert(surface_height(ddl
->ds
) == h
);
473 dbus_scanout_share_d3d_texture(ddl
, d3d_tex2d
, backing_y_0_top
,
474 backing_width
, backing_height
, x
, y
, w
, h
);
476 dbus_scanout_map(ddl
);
477 egl_fb_setup_for_tex(&ddl
->fb
, backing_width
, backing_height
, tex_id
, false);
483 static void dbus_cursor_dmabuf(DisplayChangeListener
*dcl
,
484 QemuDmaBuf
*dmabuf
, bool have_hot
,
485 uint32_t hot_x
, uint32_t hot_y
)
487 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
489 GVariant
*v_data
= NULL
;
490 egl_fb cursor_fb
= EGL_FB_INIT
;
491 uint32_t width
, height
, texture
;
494 qemu_dbus_display1_listener_call_mouse_set(
495 ddl
->proxy
, 0, 0, false,
496 G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
500 egl_dmabuf_import_texture(dmabuf
);
501 texture
= qemu_dmabuf_get_texture(dmabuf
);
506 width
= qemu_dmabuf_get_width(dmabuf
);
507 height
= qemu_dmabuf_get_height(dmabuf
);
509 egl_fb_setup_for_tex(&cursor_fb
, width
, height
, texture
, false);
510 ds
= qemu_create_displaysurface(width
, height
);
511 egl_fb_read(ds
, &cursor_fb
);
513 v_data
= g_variant_new_from_data(
514 G_VARIANT_TYPE("ay"),
516 surface_width(ds
) * surface_height(ds
) * 4,
518 (GDestroyNotify
)qemu_free_displaysurface
,
520 qemu_dbus_display1_listener_call_cursor_define(
527 G_DBUS_CALL_FLAGS_NONE
,
534 static void dbus_release_dmabuf(DisplayChangeListener
*dcl
,
537 dbus_scanout_disable(dcl
);
541 static void dbus_gl_cursor_position(DisplayChangeListener
*dcl
,
542 uint32_t pos_x
, uint32_t pos_y
)
544 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
546 qemu_dbus_display1_listener_call_mouse_set(
547 ddl
->proxy
, pos_x
, pos_y
, true,
548 G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
551 static void dbus_scanout_update(DisplayChangeListener
*dcl
,
552 uint32_t x
, uint32_t y
,
553 uint32_t w
, uint32_t h
)
555 dbus_call_update_gl(dcl
, x
, y
, w
, h
);
558 static void dbus_gl_refresh(DisplayChangeListener
*dcl
)
560 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
562 graphic_hw_update(dcl
->con
);
564 if (!ddl
->ds
|| qemu_console_is_gl_blocked(ddl
->dcl
.con
)) {
569 int n_rects
= pixman_region32_n_rects(&ddl
->gl_damage
);
571 for (int i
= 0; i
< n_rects
; i
++) {
573 box
= pixman_region32_rectangles(&ddl
->gl_damage
, NULL
) + i
;
574 /* TODO: Add a UpdateList call to send multiple updates at once */
575 dbus_call_update_gl(dcl
, box
->x1
, box
->y1
,
576 box
->x2
- box
->x1
, box
->y2
- box
->y1
);
578 pixman_region32_clear(&ddl
->gl_damage
);
580 if (ddl
->gl_damage
) {
581 dbus_call_update_gl(dcl
, 0, 0,
582 surface_width(ddl
->ds
), surface_height(ddl
->ds
));
589 static void dbus_refresh(DisplayChangeListener
*dcl
)
591 graphic_hw_update(dcl
->con
);
595 static void dbus_gl_gfx_update(DisplayChangeListener
*dcl
,
596 int x
, int y
, int w
, int h
)
598 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
601 pixman_region32_t rect_region
;
602 pixman_region32_init_rect(&rect_region
, x
, y
, w
, h
);
603 pixman_region32_union(&ddl
->gl_damage
, &ddl
->gl_damage
, &rect_region
);
604 pixman_region32_fini(&rect_region
);
611 static void dbus_gfx_update_sub(DBusDisplayListener
*ddl
,
612 int x
, int y
, int w
, int h
)
618 /* make a copy, since gvariant only handles linear data */
619 stride
= w
* DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl
->ds
)), 8);
620 img
= pixman_image_create_bits(surface_format(ddl
->ds
),
623 pixman_image_composite(PIXMAN_OP_SRC
, ddl
->ds
->image
, NULL
, img
,
624 x
, y
, 0, 0, 0, 0, w
, h
);
627 uint8_t *src
= (uint8_t *)pixman_image_get_data(ddl
->ds
->image
);
628 uint8_t *dst
= (uint8_t *)pixman_image_get_data(img
);
629 int bp
= PIXMAN_FORMAT_BPP(surface_format(ddl
->ds
)) / 8;
632 for (hh
= 0; hh
< h
; hh
++) {
633 memcpy(&dst
[stride
* hh
],
634 &src
[surface_stride(ddl
->ds
) * (hh
+ y
) + x
* bp
],
639 v_data
= g_variant_new_from_data(
640 G_VARIANT_TYPE("ay"),
641 pixman_image_get_data(img
),
642 pixman_image_get_stride(img
) * h
,
644 (GDestroyNotify
)pixman_image_unref
,
646 qemu_dbus_display1_listener_call_update(ddl
->proxy
,
647 x
, y
, w
, h
, pixman_image_get_stride(img
), pixman_image_get_format(img
),
649 G_DBUS_CALL_FLAGS_NONE
,
650 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
653 static void ddl_scanout(DBusDisplayListener
*ddl
)
657 v_data
= g_variant_new_from_data(
658 G_VARIANT_TYPE("ay"), surface_data(ddl
->ds
),
659 surface_stride(ddl
->ds
) * surface_height(ddl
->ds
), TRUE
,
660 (GDestroyNotify
)pixman_image_unref
, pixman_image_ref(ddl
->ds
->image
));
662 ddl_discard_pending_messages(ddl
);
664 qemu_dbus_display1_listener_call_scanout(
665 ddl
->proxy
, surface_width(ddl
->ds
), surface_height(ddl
->ds
),
666 surface_stride(ddl
->ds
), surface_format(ddl
->ds
), v_data
,
667 G_DBUS_CALL_FLAGS_NONE
, DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
,
671 static void dbus_gfx_update(DisplayChangeListener
*dcl
,
672 int x
, int y
, int w
, int h
)
674 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
678 trace_dbus_update(x
, y
, w
, h
);
681 if (dbus_scanout_map(ddl
)) {
682 qemu_dbus_display1_listener_win32_map_call_update_map(
685 G_DBUS_CALL_FLAGS_NONE
,
686 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
691 if (x
== 0 && y
== 0 && w
== surface_width(ddl
->ds
) && h
== surface_height(ddl
->ds
)) {
692 return ddl_scanout(ddl
);
695 dbus_gfx_update_sub(ddl
, x
, y
, w
, h
);
699 static void dbus_gl_gfx_switch(DisplayChangeListener
*dcl
,
700 struct DisplaySurface
*new_surface
)
702 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
704 trace_dbus_gl_gfx_switch(new_surface
);
706 ddl
->ds
= new_surface
;
707 ddl
->ds_share
= SHARE_KIND_NONE
;
709 int width
= surface_width(ddl
->ds
);
710 int height
= surface_height(ddl
->ds
);
712 /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
713 dbus_scanout_texture(&ddl
->dcl
, ddl
->ds
->texture
, false,
714 width
, height
, 0, 0, width
, height
, NULL
);
719 static void dbus_gfx_switch(DisplayChangeListener
*dcl
,
720 struct DisplaySurface
*new_surface
)
722 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
724 ddl
->ds
= new_surface
;
725 ddl
->ds_share
= SHARE_KIND_NONE
;
728 static void dbus_mouse_set(DisplayChangeListener
*dcl
,
729 int x
, int y
, int on
)
731 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
733 qemu_dbus_display1_listener_call_mouse_set(
734 ddl
->proxy
, x
, y
, on
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
737 static void dbus_cursor_define(DisplayChangeListener
*dcl
,
740 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
741 GVariant
*v_data
= NULL
;
743 v_data
= g_variant_new_from_data(
744 G_VARIANT_TYPE("ay"),
746 c
->width
* c
->height
* 4,
748 (GDestroyNotify
)cursor_unref
,
751 qemu_dbus_display1_listener_call_cursor_define(
758 G_DBUS_CALL_FLAGS_NONE
,
766 const DisplayChangeListenerOps dbus_gl_dcl_ops
= {
767 .dpy_name
= "dbus-gl",
768 .dpy_gfx_update
= dbus_gl_gfx_update
,
769 .dpy_gfx_switch
= dbus_gl_gfx_switch
,
770 .dpy_gfx_check_format
= console_gl_check_format
,
771 .dpy_refresh
= dbus_gl_refresh
,
772 .dpy_mouse_set
= dbus_mouse_set
,
773 .dpy_cursor_define
= dbus_cursor_define
,
775 .dpy_gl_scanout_disable
= dbus_scanout_disable
,
776 .dpy_gl_scanout_texture
= dbus_scanout_texture
,
778 .dpy_gl_scanout_dmabuf
= dbus_scanout_dmabuf
,
779 .dpy_gl_cursor_dmabuf
= dbus_cursor_dmabuf
,
780 .dpy_gl_release_dmabuf
= dbus_release_dmabuf
,
782 .dpy_gl_cursor_position
= dbus_gl_cursor_position
,
783 .dpy_gl_update
= dbus_scanout_update
,
787 const DisplayChangeListenerOps dbus_dcl_ops
= {
789 .dpy_gfx_update
= dbus_gfx_update
,
790 .dpy_gfx_switch
= dbus_gfx_switch
,
791 .dpy_refresh
= dbus_refresh
,
792 .dpy_mouse_set
= dbus_mouse_set
,
793 .dpy_cursor_define
= dbus_cursor_define
,
797 dbus_display_listener_dispose(GObject
*object
)
799 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(object
);
801 unregister_displaychangelistener(&ddl
->dcl
);
802 g_clear_object(&ddl
->conn
);
803 g_clear_pointer(&ddl
->bus_name
, g_free
);
804 g_clear_object(&ddl
->proxy
);
806 g_clear_object(&ddl
->map_proxy
);
807 g_clear_object(&ddl
->d3d11_proxy
);
808 g_clear_pointer(&ddl
->peer_process
, CloseHandle
);
810 pixman_region32_fini(&ddl
->gl_damage
);
813 egl_fb_destroy(&ddl
->fb
);
817 G_OBJECT_CLASS(dbus_display_listener_parent_class
)->dispose(object
);
821 dbus_display_listener_constructed(GObject
*object
)
823 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(object
);
825 ddl
->dcl
.ops
= &dbus_dcl_ops
;
827 if (display_opengl
) {
828 ddl
->dcl
.ops
= &dbus_gl_dcl_ops
;
832 G_OBJECT_CLASS(dbus_display_listener_parent_class
)->constructed(object
);
836 dbus_display_listener_class_init(DBusDisplayListenerClass
*klass
)
838 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
840 object_class
->dispose
= dbus_display_listener_dispose
;
841 object_class
->constructed
= dbus_display_listener_constructed
;
845 dbus_display_listener_init(DBusDisplayListener
*ddl
)
848 pixman_region32_init(&ddl
->gl_damage
);
853 dbus_display_listener_get_bus_name(DBusDisplayListener
*ddl
)
855 return ddl
->bus_name
?: "p2p";
859 dbus_display_listener_get_console(DBusDisplayListener
*ddl
)
866 dbus_display_listener_implements(DBusDisplayListener
*ddl
, const char *iface
)
868 QemuDBusDisplay1Listener
*l
= QEMU_DBUS_DISPLAY1_LISTENER(ddl
->proxy
);
871 implements
= g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l
), iface
);
873 g_debug("Display listener does not implement: `%s`", iface
);
880 dbus_display_listener_setup_peer_process(DBusDisplayListener
*ddl
)
882 g_autoptr(GError
) err
= NULL
;
883 GDBusConnection
*conn
;
886 g_autoptr(GCredentials
) creds
= NULL
;
889 if (ddl
->peer_process
) {
893 conn
= g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl
->proxy
));
894 stream
= g_dbus_connection_get_stream(conn
);
896 if (!G_IS_UNIX_CONNECTION(stream
)) {
900 sock
= g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream
));
901 creds
= g_socket_get_credentials(sock
, &err
);
904 g_debug("Failed to get peer credentials: %s", err
->message
);
908 pid
= g_credentials_get_native(creds
, G_CREDENTIALS_TYPE_WIN32_PID
);
911 g_debug("Failed to get peer PID");
915 ddl
->peer_process
= OpenProcess(
916 PROCESS_DUP_HANDLE
| PROCESS_QUERY_INFORMATION
,
919 if (!ddl
->peer_process
) {
920 g_autofree
char *msg
= g_win32_error_message(GetLastError());
921 g_debug("Failed to OpenProcess: %s", msg
);
930 dbus_display_listener_setup_d3d11(DBusDisplayListener
*ddl
)
933 g_autoptr(GError
) err
= NULL
;
935 if (!dbus_display_listener_implements(ddl
,
936 "org.qemu.Display1.Listener.Win32.D3d11")) {
940 if (!dbus_display_listener_setup_peer_process(ddl
)) {
945 qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl
->conn
,
946 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
948 "/org/qemu/Display1/Listener",
951 if (!ddl
->d3d11_proxy
) {
952 g_debug("Failed to setup win32 d3d11 proxy: %s", err
->message
);
959 dbus_display_listener_setup_shared_map(DBusDisplayListener
*ddl
)
962 g_autoptr(GError
) err
= NULL
;
964 if (!dbus_display_listener_implements(ddl
, "org.qemu.Display1.Listener.Win32.Map")) {
968 if (!dbus_display_listener_setup_peer_process(ddl
)) {
973 qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl
->conn
,
974 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
976 "/org/qemu/Display1/Listener",
979 if (!ddl
->map_proxy
) {
980 g_debug("Failed to setup win32 map proxy: %s", err
->message
);
984 ddl
->can_share_map
= true;
988 static GDBusMessage
*
989 dbus_filter(GDBusConnection
*connection
,
990 GDBusMessage
*message
,
994 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(user_data
);
1001 serial
= g_dbus_message_get_serial(message
);
1002 if (serial
<= ddl
->out_serial_to_discard
) {
1003 trace_dbus_filter(serial
, ddl
->out_serial_to_discard
);
1010 DBusDisplayListener
*
1011 dbus_display_listener_new(const char *bus_name
,
1012 GDBusConnection
*conn
,
1013 DBusDisplayConsole
*console
)
1015 DBusDisplayListener
*ddl
;
1017 g_autoptr(GError
) err
= NULL
;
1019 ddl
= g_object_new(DBUS_DISPLAY_TYPE_LISTENER
, NULL
);
1021 qemu_dbus_display1_listener_proxy_new_sync(conn
,
1022 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
1024 "/org/qemu/Display1/Listener",
1028 error_report("Failed to setup proxy: %s", err
->message
);
1029 g_object_unref(conn
);
1030 g_object_unref(ddl
);
1034 ddl
->dbus_filter
= g_dbus_connection_add_filter(conn
, dbus_filter
, g_object_ref(ddl
), g_object_unref
);
1035 ddl
->bus_name
= g_strdup(bus_name
);
1037 ddl
->console
= console
;
1039 dbus_display_listener_setup_shared_map(ddl
);
1040 dbus_display_listener_setup_d3d11(ddl
);
1042 con
= qemu_console_lookup_by_index(dbus_display_console_get_index(console
));
1045 register_displaychangelistener(&ddl
->dcl
);