From nobody Tue Feb 10 19:15:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1686053416; cv=none; d=zohomail.com; s=zohoarc; b=LR1UiIevHiWCot7uyzKe3mo+R3FbSqdJMoV4Gm2hxAIGK0MIbDgBeQAPh8sDPMazhZ2/d5QQ3BXQZDF+cTw3D/CTWbPBgDxCm01xsI+UyaKE7Be2AinkPi/3niGajW0XZ5nSpB4M2/MUMJ96ZJ5KJk47p7T9N2K2W113QDZPHKU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1686053416; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=uJudALhDWUg04cA4HnvAPUVqeo2eRJiJEpfV9OZsZIc=; b=MjM0gPHhKnl0E+gPDuhniMZzszDJr4ACW3CUjkWdIQzEJ+DBg+QnhgaStTFxiFuZMyYaJ3FyU8/3UDz75aNoONxl0HuFkEg5jeDk5LtPwcgK14H4ksURHywbS19k7ZlMyCxY0uqFC667bkbVFARz3apZDJWxiQi+upFS6Z/gfy8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 16860534163791011.9168217203328; Tue, 6 Jun 2023 05:10:16 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1q6VLs-0003BJ-7z; Tue, 06 Jun 2023 07:59:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q6VL5-0002Y2-K3 for qemu-devel@nongnu.org; Tue, 06 Jun 2023 07:59:05 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q6VL2-0006A3-IW for qemu-devel@nongnu.org; Tue, 06 Jun 2023 07:59:02 -0400 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-654-KkwWIDkUM8CSDnnhNN3JqQ-1; Tue, 06 Jun 2023 07:58:59 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B16791C01E82 for ; Tue, 6 Jun 2023 11:58:58 +0000 (UTC) Received: from localhost (unknown [10.39.208.7]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3422E2026D6A; Tue, 6 Jun 2023 11:58:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686052740; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uJudALhDWUg04cA4HnvAPUVqeo2eRJiJEpfV9OZsZIc=; b=gxd8cCesZAmIfRX7j7FWvaoI1j8B2XaNW64r6Bv13HkIN+SlcP5GDqxyvit/092pDNVDbP ZsODKkJxrgehXGuiHezjnXrs/TvUw3+by3w7xVFNMY2tTXly7JHkfQk5egWlQmjZCvIX2k X2rJzPR/3vFij0uR1AOYZiM7wvd7/gw= X-MC-Unique: KkwWIDkUM8CSDnnhNN3JqQ-1 From: marcandre.lureau@redhat.com To: qemu-devel@nongnu.org Cc: Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [PATCH 21/21] ui/dbus: use shared D3D11 Texture2D when possible Date: Tue, 6 Jun 2023 15:56:58 +0400 Message-Id: <20230606115658.677673-22-marcandre.lureau@redhat.com> In-Reply-To: <20230606115658.677673-1-marcandre.lureau@redhat.com> References: <20230606115658.677673-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=marcandre.lureau@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1686053419524100003 From: Marc-Andr=C3=A9 Lureau 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=C3=A9 Lureau --- 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 #endif +#ifdef WIN32 +#include +#include +#endif =20 #ifdef CONFIG_OPENGL #include "ui/shader.h" @@ -39,6 +44,12 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, struct DisplaySurface *new_surface); =20 +enum share_kind { + SHARE_KIND_NONE, + SHARE_KIND_MAPPED, + SHARE_KIND_D3DTEX, +}; + struct _DBusDisplayListener { GObject parent; =20 @@ -50,6 +61,8 @@ struct _DBusDisplayListener { =20 DisplayChangeListener dcl; DisplaySurface *ds; + enum share_kind ds_share; + int gl_updates; =20 bool ds_mapped; @@ -57,7 +70,9 @@ struct _DBusDisplayListener { =20 #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 =3D container_of(dcl, DBusDisplayListener, dc= l); =20 - ddl->ds =3D NULL; qemu_dbus_display1_listener_call_disable( ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } =20 -#ifdef CONFIG_GBM +#ifdef WIN32 +static bool d3d_texture2d_share(ID3D11Texture2D *d3d_texture, + HANDLE *handle, Error **errp) +{ + IDXGIResource1 *dxgiResource =3D NULL; + HRESULT hr; + + hr =3D d3d_texture->lpVtbl->QueryInterface(d3d_texture, + &IID_IDXGIResource1, + (void **)&dxgiResource); + if (FAILED(hr)) { + goto fail; + } + + hr =3D 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 **e= rrp) +{ + IDXGIKeyedMutex *dxgiMutex =3D NULL; + HRESULT hr; + + hr =3D d3d_texture->lpVtbl->QueryInterface(d3d_texture, + &IID_IDXGIKeyedMutex, + (void **)&dxgiMutex); + if (FAILED(hr)) { + goto fail; + } + + hr =3D 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 mute= x"); + return false; +} + +static bool d3d_texture2d_release0(ID3D11Texture2D *d3d_texture, Error **e= rrp) +{ + IDXGIKeyedMutex *dxgiMutex =3D NULL; + HRESULT hr; + + hr =3D d3d_texture->lpVtbl->QueryInterface(d3d_texture, + &IID_IDXGIKeyedMutex, + (void **)&dxgiMutex); + if (FAILED(hr)) { + goto fail; + } + + hr =3D dxgiMutex->lpVtbl->ReleaseSync(dxgiMutex, 0); + + dxgiMutex->lpVtbl->Release(dxgiMutex); + + if (SUCCEEDED(hr)) { + return true; + } + +fail: + error_setg_win32(errp, GetLastError(), "failed to release texture mute= x"); + 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 =3D NULL; DBusDisplayListener *ddl =3D user_data; + bool success; + +#ifdef CONFIG_GBM + success =3D qemu_dbus_display1_listener_call_update_dmabuf_finish( + ddl->proxy, res, &err); +#endif + +#ifdef WIN32 + success =3D qemu_dbus_display1_listener_win32_d3d11_call_update_textur= e2d_finish( + ddl->d3d11_proxy, res, &err); + d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn); +#endif =20 - if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy, - res, &err))= { + if (!success) { error_report("Failed to call update: %s", err->message); } =20 graphic_hw_gl_block(ddl->dcl.con, false); g_object_unref(ddl); } -#endif =20 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 =20 #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 =3D 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 } =20 @@ -160,7 +290,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl) BOOL success; HANDLE target_handle; =20 - if (ddl->ds_mapped) { + if (ddl->ds_share =3D=3D SHARE_KIND_MAPPED) { return true; } =20 @@ -199,7 +329,69 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl) return false; } =20 - ddl->ds_mapped =3D true; + ddl->ds_share =3D 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 =3D 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 =3D DuplicateHandle( + GetCurrentProcess(), + share_handle, + ddl->peer_process, + &target_handle, + 0, + FALSE, DUPLICATE_SAME_ACCESS); + if (!success) { + g_autofree char *msg =3D 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 =3D tex; + ddl->ds_share =3D SHARE_KIND_D3DTEX; =20 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) =3D=3D w); assert(surface_height(ddl->ds) =3D=3D 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 } =20 @@ -429,6 +628,7 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *d= cl, trace_dbus_gl_gfx_switch(new_surface); =20 ddl->ds =3D new_surface; + ddl->ds_share =3D SHARE_KIND_NONE; if (ddl->ds) { int width =3D surface_width(ddl->ds); int height =3D surface_height(ddl->ds); @@ -446,13 +646,7 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, DBusDisplayListener *ddl =3D container_of(dcl, DBusDisplayListener, dc= l); =20 ddl->ds =3D new_surface; -#ifdef WIN32 - ddl->ds_mapped =3D false; -#endif - if (!ddl->ds) { - /* why not call disable instead? */ - return; - } + ddl->ds_share =3D SHARE_KIND_NONE; } =20 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) =20 return implements; } -#endif =20 -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 =3D NULL; GDBusConnection *conn; GIOStream *stream; @@ -611,15 +804,15 @@ dbus_display_listener_setup_shared_map(DBusDisplayLis= tener *ddl) g_autoptr(GCredentials) creds =3D NULL; DWORD *pid; =20 - if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener= .Win32.Map")) { - return; + if (ddl->peer_process) { + return true; } =20 conn =3D g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)); stream =3D g_dbus_connection_get_stream(conn); =20 if (!G_IS_UNIX_CONNECTION(stream)) { - return; + return false; } =20 sock =3D g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream)); @@ -627,14 +820,14 @@ dbus_display_listener_setup_shared_map(DBusDisplayLis= tener *ddl) =20 if (!creds) { g_debug("Failed to get peer credentials: %s", err->message); - return; + return false; } =20 pid =3D g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID); =20 if (pid =3D=3D NULL) { g_debug("Failed to get peer PID"); - return; + return false; } =20 ddl->peer_process =3D OpenProcess( @@ -644,11 +837,58 @@ dbus_display_listener_setup_shared_map(DBusDisplayLis= tener *ddl) if (!ddl->peer_process) { g_autofree char *msg =3D 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 =3D 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 =3D + 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 =3D NULL; + + if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener= .Win32.Map")) { + return; + } + + if (!dbus_display_listener_setup_peer_process(ddl)) { return; } =20 ddl->map_proxy =3D - 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 =3D console; =20 dbus_display_listener_setup_shared_map(ddl); + dbus_display_listener_setup_d3d11(ddl); =20 con =3D qemu_console_lookup_by_index(dbus_display_console_get_index(co= nsole)); assert(con); diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml index 2aba36fee0..4a4803a30a 100644 --- a/ui/dbus-display1.xml +++ b/ui/dbus-display1.xml @@ -431,8 +431,9 @@ + + + + + + + + + + + + + + + + + + + + + +