diff options
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/console.c | 137 | ||||
| -rw-r--r-- | ui/dbus-chardev.c | 20 | ||||
| -rw-r--r-- | ui/dbus-console.c | 124 | ||||
| -rw-r--r-- | ui/dbus-display1.xml | 285 | ||||
| -rw-r--r-- | ui/dbus-listener.c | 527 | ||||
| -rw-r--r-- | ui/dbus.c | 4 | ||||
| -rw-r--r-- | ui/dbus.h | 6 | ||||
| -rw-r--r-- | ui/egl-context.c | 10 | ||||
| -rw-r--r-- | ui/egl-headless.c | 25 | ||||
| -rw-r--r-- | ui/egl-helpers.c | 104 | ||||
| -rw-r--r-- | ui/gtk-egl.c | 16 | ||||
| -rw-r--r-- | ui/gtk-gl-area.c | 6 | ||||
| -rw-r--r-- | ui/gtk.c | 66 | ||||
| -rw-r--r-- | ui/meson.build | 15 | ||||
| -rw-r--r-- | ui/qemu-pixman.c | 1 | ||||
| -rw-r--r-- | ui/sdl2-gl.c | 3 | ||||
| -rw-r--r-- | ui/sdl2.c | 18 | ||||
| -rw-r--r-- | ui/spice-display.c | 3 | ||||
| -rw-r--r-- | ui/trace-events | 9 |
19 files changed, 1211 insertions, 168 deletions
diff --git a/ui/console.c b/ui/console.c index e173731e20..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); } } @@ -1513,18 +1514,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 +1582,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; } @@ -1635,6 +1681,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 */ @@ -2005,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; @@ -2013,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)) { @@ -2023,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); } } } @@ -2306,7 +2419,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) diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c index 940ef937cd..1d3a7122a1 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" @@ -112,13 +114,20 @@ 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( @@ -128,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; } @@ -142,7 +156,11 @@ 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; } diff --git a/ui/dbus-console.c b/ui/dbus-console.c index f77bc49d2e..e19774f985 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -28,10 +28,14 @@ #include "ui/kbd-state.h" #include "trace.h" +#ifdef G_OS_UNIX #include <gio/gunixfdlist.h> +#endif #include "dbus.h" +static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX]; + struct _DBusDisplayConsole { GDBusObjectSkeleton parent_instance; DisplayChangeListener dcl; @@ -44,6 +48,7 @@ struct _DBusDisplayConsole { QKbdState *kbd; QemuDBusDisplay1Mouse *iface_mouse; + QemuDBusDisplay1MultiTouch *iface_touch; gboolean last_set; guint last_x; guint last_y; @@ -93,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); @@ -204,10 +210,47 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } +#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); @@ -229,6 +272,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( @@ -238,6 +286,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) { @@ -246,13 +295,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), @@ -346,6 +403,46 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc, } 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, guint x, guint y) @@ -440,7 +537,13 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con) g_autofree char *label = NULL; char device_addr[256] = ""; DBusDisplayConsole *ddc; - int idx; + int idx, i; + const char *interfaces[] = { + "org.qemu.Display1.Keyboard", + "org.qemu.Display1.Mouse", + "org.qemu.Display1.MultiTouch", + NULL + }; assert(display); assert(con); @@ -465,6 +568,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", @@ -495,6 +599,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..f0e2fac212 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> <!-- @@ -39,8 +53,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"> <!-- @@ -56,7 +71,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> <!-- @@ -120,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"> @@ -164,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: @@ -237,6 +274,46 @@ </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: This client-side interface must be available on @@ -293,6 +370,7 @@ </arg> </method> + <?if $(env.TARGETOS) != windows?> <!-- ScanoutDMABUF: @dmabuf: the DMABUF file descriptor. @@ -331,6 +409,7 @@ <arg type="i" name="width" direction="in"/> <arg type="i" name="height" direction="in"/> </method> + <?endif?> <!-- Disable: @@ -374,6 +453,116 @@ <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> + + <!-- + org.qemu.Display1.Listener.Win32.Map: + + 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"> + <!-- + 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.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> <!-- @@ -471,6 +660,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> <!-- @@ -491,7 +694,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> <!-- @@ -506,8 +715,28 @@ :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> + + <!-- + 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> <!-- @@ -594,6 +823,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> <!-- @@ -682,6 +925,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> <!-- @@ -719,7 +976,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> <!-- @@ -757,5 +1020,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> diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 23034eebf9..e10162b279 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -23,9 +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" @@ -34,6 +41,15 @@ #endif #include "trace.h" +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; @@ -45,21 +61,142 @@ struct _DBusDisplayListener { DisplayChangeListener dcl; DisplaySurface *ds; + enum share_kind ds_share; + int gl_updates; + + bool ds_mapped; + bool can_share_map; + +#ifdef WIN32 + QemuDBusDisplay1ListenerWin32Map *map_proxy; + QemuDBusDisplay1ListenerWin32D3d11 *d3d11_proxy; + HANDLE peer_process; + ID3D11Texture2D *d3d_texture; +#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); + + qemu_dbus_display1_listener_call_disable( + ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); +} + +#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); } @@ -67,28 +204,54 @@ static void dbus_update_gl_cb(GObject *source_object, g_object_unref(ddl); } -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); + + trace_dbus_update_gl(x, y, w, h); + 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 + 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 } +#ifdef CONFIG_GBM static void dbus_scanout_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf) { @@ -117,15 +280,136 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl, fd_list, NULL, NULL, NULL); } +#endif /* GBM */ +#endif /* OPENGL */ + +#ifdef WIN32 +static bool dbus_scanout_map(DBusDisplayListener *ddl) +{ + g_autoptr(GError) err = NULL; + BOOL success; + HANDLE target_handle; + + if (ddl->ds_share == SHARE_KIND_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_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; +} +#endif +#ifdef CONFIG_OPENGL static void dbus_scanout_texture(DisplayChangeListener *dcl, 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) + 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); +#ifdef CONFIG_GBM QemuDmaBuf dmabuf = { .width = backing_width, .height = backing_height, @@ -148,8 +432,26 @@ 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); + + 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 } +#ifdef CONFIG_GBM static void dbus_cursor_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf, bool have_hot, uint32_t hot_x, uint32_t hot_y) @@ -196,7 +498,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); @@ -206,19 +515,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) @@ -232,19 +533,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 +#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) { @@ -263,10 +564,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"), @@ -288,6 +599,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, @@ -307,20 +619,23 @@ 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) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, 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); /* 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 @@ -331,10 +646,7 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); ddl->ds = new_surface; - if (!ddl->ds) { - /* why not call disable instead? */ - return; - } + ddl->ds_share = SHARE_KIND_NONE; } static void dbus_mouse_set(DisplayChangeListener *dcl, @@ -374,7 +686,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, @@ -386,10 +698,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 @@ -412,6 +726,14 @@ 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_object(&ddl->d3d11_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); } @@ -422,7 +744,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; } @@ -457,6 +779,130 @@ 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; +} + +static bool +dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl) +{ + g_autoptr(GError) err = NULL; + GDBusConnection *conn; + GIOStream *stream; + GSocket *sock; + g_autoptr(GCredentials) creds = NULL; + DWORD *pid; + + 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 false; + } + + 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 false; + } + + pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID); + + if (pid == NULL) { + g_debug("Failed to get peer PID"); + return false; + } + + 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 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(ddl->conn, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + "/org/qemu/Display1/Listener", + NULL, + &err); + if (!ddl->map_proxy) { + g_debug("Failed to setup win32 map proxy: %s", err->message); + return; + } + + ddl->can_share_map = true; +#endif +} + DBusDisplayListener * dbus_display_listener_new(const char *bus_name, GDBusConnection *conn, @@ -485,6 +931,9 @@ dbus_display_listener_new(const char *bus_name, ddl->conn = conn; 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); ddl->dcl.con = con; 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; } 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/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/egl-headless.c b/ui/egl-headless.c index ef70e6a18e..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); @@ -79,6 +80,8 @@ static void egl_scanout_texture(DisplayChangeListener *dcl, } } +#ifdef CONFIG_GBM + static void egl_scanout_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf) { @@ -89,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, @@ -110,6 +113,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 +130,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 +165,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 4203163ace..8f9fbf583e 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -15,21 +15,23 @@ * 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; /* ------------------------------------------------------------------ */ -#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 +70,6 @@ static const char *egl_get_error_string(void) return "Unknown EGL error"; } } -#endif static void egl_fb_delete_texture(egl_fb *fb) { @@ -171,6 +172,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); @@ -201,11 +216,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) { @@ -402,7 +418,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 @@ -439,10 +455,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); } } @@ -482,20 +496,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; } @@ -504,7 +518,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; } @@ -512,6 +526,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 @@ -529,7 +546,45 @@ 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) +{ + /* prefer GL ES, as that's what ANGLE supports */ + if (mode == DISPLAYGL_MODE_ON) { + mode = DISPLAYGL_MODE_ES; + } + + 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 bool qemu_egl_has_dmabuf(void) @@ -581,15 +636,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/gtk-egl.c b/ui/gtk-egl.c index 19130041bc..d59b8cd7d7 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" @@ -223,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); @@ -257,7 +259,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, NULL); if (dmabuf->allow_fences) { vc->gfx.guest_fb.dmabuf = dmabuf; @@ -368,6 +371,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; } diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index c384a1516b..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); @@ -299,7 +300,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, NULL); if (dmabuf->allow_fences) { vc->gfx.guest_fb.dmabuf = dmabuf; diff --git a/ui/gtk.c b/ui/gtk.c index e50f950f2b..8ba41c8f13 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; @@ -588,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 } @@ -1068,27 +1068,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 +1084,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; } diff --git a/ui/meson.build b/ui/meson.build index a5506ac8ad..d81609fb0e 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -65,18 +65,25 @@ 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 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(), 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/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/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; } 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; diff --git a/ui/trace-events b/ui/trace-events index 6747361745..76b19a2995 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" @@ -154,7 +154,14 @@ 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_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" + +# egl-helpers.c +egl_init_d3d11_device(void *p) "d3d device: %p" |