xref: /openbmc/qemu/ui/dbus-listener.c (revision 01fff50626c2bffd7be1ce92e531852ea69372f3)
1142ca628SMarc-André Lureau /*
2142ca628SMarc-André Lureau  * QEMU DBus display console
3142ca628SMarc-André Lureau  *
4142ca628SMarc-André Lureau  * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com>
5142ca628SMarc-André Lureau  *
6142ca628SMarc-André Lureau  * Permission is hereby granted, free of charge, to any person obtaining a copy
7142ca628SMarc-André Lureau  * of this software and associated documentation files (the "Software"), to deal
8142ca628SMarc-André Lureau  * in the Software without restriction, including without limitation the rights
9142ca628SMarc-André Lureau  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10142ca628SMarc-André Lureau  * copies of the Software, and to permit persons to whom the Software is
11142ca628SMarc-André Lureau  * furnished to do so, subject to the following conditions:
12142ca628SMarc-André Lureau  *
13142ca628SMarc-André Lureau  * The above copyright notice and this permission notice shall be included in
14142ca628SMarc-André Lureau  * all copies or substantial portions of the Software.
15142ca628SMarc-André Lureau  *
16142ca628SMarc-André Lureau  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17142ca628SMarc-André Lureau  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18142ca628SMarc-André Lureau  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19142ca628SMarc-André Lureau  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20142ca628SMarc-André Lureau  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21142ca628SMarc-André Lureau  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22142ca628SMarc-André Lureau  * THE SOFTWARE.
23142ca628SMarc-André Lureau  */
24142ca628SMarc-André Lureau #include "qemu/osdep.h"
255feed38cSThomas Huth #include "qemu/error-report.h"
26de1f8ce0SMarc-André Lureau #include "qapi/error.h"
27142ca628SMarc-André Lureau #include "sysemu/sysemu.h"
28142ca628SMarc-André Lureau #include "dbus.h"
29*01fff506SMarc-André Lureau #include "glib.h"
3029c5c7e5SMarc-André Lureau #ifdef G_OS_UNIX
31142ca628SMarc-André Lureau #include <gio/gunixfdlist.h>
3229c5c7e5SMarc-André Lureau #endif
33de1f8ce0SMarc-André Lureau #ifdef WIN32
34de1f8ce0SMarc-André Lureau #include <d3d11.h>
35de1f8ce0SMarc-André Lureau #include <dxgi1_2.h>
36de1f8ce0SMarc-André Lureau #endif
37142ca628SMarc-André Lureau 
3884a0a2efSMarc-André Lureau #ifdef CONFIG_OPENGL
39142ca628SMarc-André Lureau #include "ui/shader.h"
40142ca628SMarc-André Lureau #include "ui/egl-helpers.h"
41142ca628SMarc-André Lureau #include "ui/egl-context.h"
42949c084aSMarc-André Lureau #include "ui/qemu-pixman.h"
4384a0a2efSMarc-André Lureau #endif
44142ca628SMarc-André Lureau #include "trace.h"
45142ca628SMarc-André Lureau 
46f43bf0a7SMarc-André Lureau static void dbus_gfx_switch(DisplayChangeListener *dcl,
47f43bf0a7SMarc-André Lureau                             struct DisplaySurface *new_surface);
48f43bf0a7SMarc-André Lureau 
49de1f8ce0SMarc-André Lureau enum share_kind {
50de1f8ce0SMarc-André Lureau     SHARE_KIND_NONE,
51de1f8ce0SMarc-André Lureau     SHARE_KIND_MAPPED,
52de1f8ce0SMarc-André Lureau     SHARE_KIND_D3DTEX,
53de1f8ce0SMarc-André Lureau };
54de1f8ce0SMarc-André Lureau 
55142ca628SMarc-André Lureau struct _DBusDisplayListener {
56142ca628SMarc-André Lureau     GObject parent;
57142ca628SMarc-André Lureau 
58142ca628SMarc-André Lureau     char *bus_name;
59142ca628SMarc-André Lureau     DBusDisplayConsole *console;
60142ca628SMarc-André Lureau     GDBusConnection *conn;
61142ca628SMarc-André Lureau 
62142ca628SMarc-André Lureau     QemuDBusDisplay1Listener *proxy;
63142ca628SMarc-André Lureau 
64949c084aSMarc-André Lureau #ifdef CONFIG_PIXMAN
657007e98cSBilal Elmoussaoui     /* Keep track of the damage region */
667007e98cSBilal Elmoussaoui     pixman_region32_t gl_damage;
67949c084aSMarc-André Lureau #else
68949c084aSMarc-André Lureau     int gl_damage;
697007e98cSBilal Elmoussaoui #endif
707007e98cSBilal Elmoussaoui 
71142ca628SMarc-André Lureau     DisplayChangeListener dcl;
72142ca628SMarc-André Lureau     DisplaySurface *ds;
73de1f8ce0SMarc-André Lureau     enum share_kind ds_share;
74de1f8ce0SMarc-André Lureau 
7548dddba1SMarc-André Lureau     bool ds_mapped;
7648dddba1SMarc-André Lureau     bool can_share_map;
7748dddba1SMarc-André Lureau 
7848dddba1SMarc-André Lureau #ifdef WIN32
7948dddba1SMarc-André Lureau     QemuDBusDisplay1ListenerWin32Map *map_proxy;
80de1f8ce0SMarc-André Lureau     QemuDBusDisplay1ListenerWin32D3d11 *d3d11_proxy;
8148dddba1SMarc-André Lureau     HANDLE peer_process;
82de1f8ce0SMarc-André Lureau     ID3D11Texture2D *d3d_texture;
83f43bf0a7SMarc-André Lureau #ifdef CONFIG_OPENGL
84f43bf0a7SMarc-André Lureau     egl_fb fb;
85f43bf0a7SMarc-André Lureau #endif
8648dddba1SMarc-André Lureau #else /* !WIN32 */
87fa88b85dSMarc-André Lureau     QemuDBusDisplay1ListenerUnixMap *map_proxy;
88fa88b85dSMarc-André Lureau #endif
89*01fff506SMarc-André Lureau 
90142ca628SMarc-André Lureau     guint dbus_filter;
91142ca628SMarc-André Lureau     guint32 display_serial_to_discard;
92142ca628SMarc-André Lureau     guint32 cursor_serial_to_discard;
93142ca628SMarc-André Lureau };
94f43bf0a7SMarc-André Lureau 
95f43bf0a7SMarc-André Lureau G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
96f43bf0a7SMarc-André Lureau 
97*01fff506SMarc-André Lureau static void dbus_gfx_update(DisplayChangeListener *dcl,
98fa88b85dSMarc-André Lureau                             int x, int y, int w, int h);
99*01fff506SMarc-André Lureau 
ddl_discard_display_messages(DBusDisplayListener * ddl)100fa88b85dSMarc-André Lureau static void ddl_discard_display_messages(DBusDisplayListener *ddl)
101*01fff506SMarc-André Lureau {
102*01fff506SMarc-André Lureau     guint32 serial = g_dbus_connection_get_last_serial(
103fa88b85dSMarc-André Lureau         g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
104fa88b85dSMarc-André Lureau 
105f43bf0a7SMarc-André Lureau     g_atomic_int_set(&ddl->display_serial_to_discard, serial);
106f43bf0a7SMarc-André Lureau }
107f43bf0a7SMarc-André Lureau 
ddl_discard_cursor_messages(DBusDisplayListener * ddl)108f43bf0a7SMarc-André Lureau static void ddl_discard_cursor_messages(DBusDisplayListener *ddl)
109f43bf0a7SMarc-André Lureau {
110f43bf0a7SMarc-André Lureau     guint32 serial = g_dbus_connection_get_last_serial(
111f43bf0a7SMarc-André Lureau         g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
112f43bf0a7SMarc-André Lureau 
113f43bf0a7SMarc-André Lureau     g_atomic_int_set(&ddl->cursor_serial_to_discard, serial);
114de1f8ce0SMarc-André Lureau }
115de1f8ce0SMarc-André Lureau 
116de1f8ce0SMarc-André Lureau #ifdef CONFIG_OPENGL
dbus_scanout_disable(DisplayChangeListener * dcl)117de1f8ce0SMarc-André Lureau static void dbus_scanout_disable(DisplayChangeListener *dcl)
118de1f8ce0SMarc-André Lureau {
119de1f8ce0SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
120de1f8ce0SMarc-André Lureau 
121de1f8ce0SMarc-André Lureau     ddl_discard_display_messages(ddl);
122de1f8ce0SMarc-André Lureau 
123de1f8ce0SMarc-André Lureau     qemu_dbus_display1_listener_call_disable(
124de1f8ce0SMarc-André Lureau         ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
125de1f8ce0SMarc-André Lureau }
126de1f8ce0SMarc-André Lureau 
127de1f8ce0SMarc-André Lureau #ifdef WIN32
d3d_texture2d_share(ID3D11Texture2D * d3d_texture,HANDLE * handle,Error ** errp)128de1f8ce0SMarc-André Lureau static bool d3d_texture2d_share(ID3D11Texture2D *d3d_texture,
129de1f8ce0SMarc-André Lureau                                 HANDLE *handle, Error **errp)
130de1f8ce0SMarc-André Lureau {
131de1f8ce0SMarc-André Lureau     IDXGIResource1 *dxgiResource = NULL;
132de1f8ce0SMarc-André Lureau     HRESULT hr;
133de1f8ce0SMarc-André Lureau 
134de1f8ce0SMarc-André Lureau     hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
135de1f8ce0SMarc-André Lureau                                              &IID_IDXGIResource1,
136de1f8ce0SMarc-André Lureau                                              (void **)&dxgiResource);
137de1f8ce0SMarc-André Lureau     if (FAILED(hr)) {
138de1f8ce0SMarc-André Lureau         goto fail;
139de1f8ce0SMarc-André Lureau     }
140de1f8ce0SMarc-André Lureau 
141de1f8ce0SMarc-André Lureau     hr = dxgiResource->lpVtbl->CreateSharedHandle(
142de1f8ce0SMarc-André Lureau         dxgiResource,
143de1f8ce0SMarc-André Lureau         NULL,
144de1f8ce0SMarc-André Lureau         DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
145de1f8ce0SMarc-André Lureau         NULL,
146de1f8ce0SMarc-André Lureau         handle
147de1f8ce0SMarc-André Lureau         );
148de1f8ce0SMarc-André Lureau 
149de1f8ce0SMarc-André Lureau     dxgiResource->lpVtbl->Release(dxgiResource);
150de1f8ce0SMarc-André Lureau 
151de1f8ce0SMarc-André Lureau     if (SUCCEEDED(hr)) {
152de1f8ce0SMarc-André Lureau         return true;
153de1f8ce0SMarc-André Lureau     }
154de1f8ce0SMarc-André Lureau 
155de1f8ce0SMarc-André Lureau fail:
156de1f8ce0SMarc-André Lureau     error_setg_win32(errp, GetLastError(), "failed to create shared handle");
157de1f8ce0SMarc-André Lureau     return false;
158de1f8ce0SMarc-André Lureau }
159de1f8ce0SMarc-André Lureau 
d3d_texture2d_acquire0(ID3D11Texture2D * d3d_texture,Error ** errp)160de1f8ce0SMarc-André Lureau static bool d3d_texture2d_acquire0(ID3D11Texture2D *d3d_texture, Error **errp)
161de1f8ce0SMarc-André Lureau {
162de1f8ce0SMarc-André Lureau     IDXGIKeyedMutex *dxgiMutex = NULL;
163de1f8ce0SMarc-André Lureau     HRESULT hr;
164de1f8ce0SMarc-André Lureau 
165de1f8ce0SMarc-André Lureau     hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
166de1f8ce0SMarc-André Lureau                                              &IID_IDXGIKeyedMutex,
167de1f8ce0SMarc-André Lureau                                              (void **)&dxgiMutex);
168de1f8ce0SMarc-André Lureau     if (FAILED(hr)) {
169de1f8ce0SMarc-André Lureau         goto fail;
170de1f8ce0SMarc-André Lureau     }
171de1f8ce0SMarc-André Lureau 
172de1f8ce0SMarc-André Lureau     hr = dxgiMutex->lpVtbl->AcquireSync(dxgiMutex, 0, INFINITE);
173de1f8ce0SMarc-André Lureau 
174de1f8ce0SMarc-André Lureau     dxgiMutex->lpVtbl->Release(dxgiMutex);
175de1f8ce0SMarc-André Lureau 
176de1f8ce0SMarc-André Lureau     if (SUCCEEDED(hr)) {
177de1f8ce0SMarc-André Lureau         return true;
178de1f8ce0SMarc-André Lureau     }
179de1f8ce0SMarc-André Lureau 
180de1f8ce0SMarc-André Lureau fail:
181de1f8ce0SMarc-André Lureau     error_setg_win32(errp, GetLastError(), "failed to acquire texture mutex");
182de1f8ce0SMarc-André Lureau     return false;
183de1f8ce0SMarc-André Lureau }
184de1f8ce0SMarc-André Lureau 
d3d_texture2d_release0(ID3D11Texture2D * d3d_texture,Error ** errp)185de1f8ce0SMarc-André Lureau static bool d3d_texture2d_release0(ID3D11Texture2D *d3d_texture, Error **errp)
186de1f8ce0SMarc-André Lureau {
187de1f8ce0SMarc-André Lureau     IDXGIKeyedMutex *dxgiMutex = NULL;
188de1f8ce0SMarc-André Lureau     HRESULT hr;
189de1f8ce0SMarc-André Lureau 
190de1f8ce0SMarc-André Lureau     hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
191de1f8ce0SMarc-André Lureau                                              &IID_IDXGIKeyedMutex,
192de1f8ce0SMarc-André Lureau                                              (void **)&dxgiMutex);
193de1f8ce0SMarc-André Lureau     if (FAILED(hr)) {
194de1f8ce0SMarc-André Lureau         goto fail;
195de1f8ce0SMarc-André Lureau     }
196de1f8ce0SMarc-André Lureau 
197de1f8ce0SMarc-André Lureau     hr = dxgiMutex->lpVtbl->ReleaseSync(dxgiMutex, 0);
198d39a84b7SRichard Henderson 
199142ca628SMarc-André Lureau     dxgiMutex->lpVtbl->Release(dxgiMutex);
200142ca628SMarc-André Lureau 
201142ca628SMarc-André Lureau     if (SUCCEEDED(hr)) {
202142ca628SMarc-André Lureau         return true;
203142ca628SMarc-André Lureau     }
204142ca628SMarc-André Lureau 
205de1f8ce0SMarc-André Lureau fail:
206142ca628SMarc-André Lureau     error_setg_win32(errp, GetLastError(), "failed to release texture mutex");
207de1f8ce0SMarc-André Lureau     return false;
208de1f8ce0SMarc-André Lureau }
209de1f8ce0SMarc-André Lureau #endif /* WIN32 */
210de1f8ce0SMarc-André Lureau 
211de1f8ce0SMarc-André Lureau #if defined(CONFIG_GBM) || defined(WIN32)
dbus_update_gl_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)212de1f8ce0SMarc-André Lureau static void dbus_update_gl_cb(GObject *source_object,
213de1f8ce0SMarc-André Lureau                               GAsyncResult *res,
214de1f8ce0SMarc-André Lureau                               gpointer user_data)
215de1f8ce0SMarc-André Lureau {
216de1f8ce0SMarc-André Lureau     g_autoptr(GError) err = NULL;
217de1f8ce0SMarc-André Lureau     DBusDisplayListener *ddl = user_data;
218de1f8ce0SMarc-André Lureau     bool success;
219142ca628SMarc-André Lureau 
220142ca628SMarc-André Lureau #ifdef CONFIG_GBM
221142ca628SMarc-André Lureau     success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
222142ca628SMarc-André Lureau         ddl->proxy, res, &err);
223142ca628SMarc-André Lureau #endif
224142ca628SMarc-André Lureau 
225d39a84b7SRichard Henderson #ifdef WIN32
226142ca628SMarc-André Lureau     success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
227f43bf0a7SMarc-André Lureau         ddl->d3d11_proxy, res, &err);
228142ca628SMarc-André Lureau     d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
229142ca628SMarc-André Lureau #endif
230d39a84b7SRichard Henderson 
231f43bf0a7SMarc-André Lureau     if (!success) {
232d39a84b7SRichard Henderson         error_report("Failed to call update: %s", err->message);
233f43bf0a7SMarc-André Lureau     }
234cf283fb4SMarc-André Lureau 
235cf283fb4SMarc-André Lureau     graphic_hw_gl_block(ddl->dcl.con, false);
236142ca628SMarc-André Lureau     g_object_unref(ddl);
237f43bf0a7SMarc-André Lureau }
238f43bf0a7SMarc-André Lureau #endif
239142ca628SMarc-André Lureau 
dbus_call_update_gl(DisplayChangeListener * dcl,int x,int y,int w,int h)240142ca628SMarc-André Lureau static void dbus_call_update_gl(DisplayChangeListener *dcl,
241142ca628SMarc-André Lureau                                 int x, int y, int w, int h)
242142ca628SMarc-André Lureau {
243142ca628SMarc-André Lureau #if defined(CONFIG_GBM) || defined(WIN32)
244142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
245f43bf0a7SMarc-André Lureau #endif
246f43bf0a7SMarc-André Lureau 
247f43bf0a7SMarc-André Lureau     trace_dbus_update_gl(x, y, w, h);
248de1f8ce0SMarc-André Lureau 
249de1f8ce0SMarc-André Lureau     glFlush();
250f43bf0a7SMarc-André Lureau #ifdef CONFIG_GBM
251f43bf0a7SMarc-André Lureau     graphic_hw_gl_block(ddl->dcl.con, true);
252de1f8ce0SMarc-André Lureau     qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy,
2537b4a3f81SMarc-André Lureau         x, y, w, h,
254de1f8ce0SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
255de1f8ce0SMarc-André Lureau         DBUS_DEFAULT_TIMEOUT, NULL,
256de1f8ce0SMarc-André Lureau         dbus_update_gl_cb,
257de1f8ce0SMarc-André Lureau         g_object_ref(ddl));
258de1f8ce0SMarc-André Lureau #endif
259de1f8ce0SMarc-André Lureau 
260de1f8ce0SMarc-André Lureau #ifdef WIN32
261de1f8ce0SMarc-André Lureau     switch (ddl->ds_share) {
262de1f8ce0SMarc-André Lureau     case SHARE_KIND_MAPPED:
263de1f8ce0SMarc-André Lureau         egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
264de1f8ce0SMarc-André Lureau         dbus_gfx_update(dcl, x, y, w, h);
265de1f8ce0SMarc-André Lureau         break;
266de1f8ce0SMarc-André Lureau     case SHARE_KIND_D3DTEX: {
267de1f8ce0SMarc-André Lureau         Error *err = NULL;
268de1f8ce0SMarc-André Lureau         assert(ddl->d3d_texture);
269de1f8ce0SMarc-André Lureau 
2707b4a3f81SMarc-André Lureau         graphic_hw_gl_block(ddl->dcl.con, true);
271de1f8ce0SMarc-André Lureau         if (!d3d_texture2d_release0(ddl->d3d_texture, &err)) {
272de1f8ce0SMarc-André Lureau             error_report_err(err);
273de1f8ce0SMarc-André Lureau             return;
274f43bf0a7SMarc-André Lureau         }
275142ca628SMarc-André Lureau         qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
276142ca628SMarc-André Lureau             ddl->d3d11_proxy,
277f43bf0a7SMarc-André Lureau             x, y, w, h,
278142ca628SMarc-André Lureau             G_DBUS_CALL_FLAGS_NONE,
279142ca628SMarc-André Lureau             DBUS_DEFAULT_TIMEOUT, NULL,
280142ca628SMarc-André Lureau             dbus_update_gl_cb,
281142ca628SMarc-André Lureau             g_object_ref(ddl));
282142ca628SMarc-André Lureau         break;
283142ca628SMarc-André Lureau     }
2846779a307SDongwon Kim     default:
2856779a307SDongwon Kim         g_warn_if_reached();
2866779a307SDongwon Kim     }
2876779a307SDongwon Kim #endif
288142ca628SMarc-André Lureau }
2896779a307SDongwon Kim 
290142ca628SMarc-André Lureau #ifdef CONFIG_GBM
dbus_scanout_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)2916779a307SDongwon Kim static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
292142ca628SMarc-André Lureau                                 QemuDmaBuf *dmabuf)
293142ca628SMarc-André Lureau {
294142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
295142ca628SMarc-André Lureau     g_autoptr(GError) err = NULL;
296*01fff506SMarc-André Lureau     g_autoptr(GUnixFDList) fd_list = NULL;
297fa88b85dSMarc-André Lureau     int fd;
2986779a307SDongwon Kim     uint32_t width, height, stride, fourcc;
2996779a307SDongwon Kim     uint64_t modifier;
3006779a307SDongwon Kim     bool y0_top;
3016779a307SDongwon Kim 
3026779a307SDongwon Kim     fd = qemu_dmabuf_get_fd(dmabuf);
3036779a307SDongwon Kim     fd_list = g_unix_fd_list_new();
3046779a307SDongwon Kim     if (g_unix_fd_list_append(fd_list, fd, &err) != 0) {
305da1d066cSMarc-André Lureau         error_report("Failed to setup dmabuf fdlist: %s", err->message);
306142ca628SMarc-André Lureau         return;
3076779a307SDongwon Kim     }
3086779a307SDongwon Kim 
3096779a307SDongwon Kim     ddl_discard_display_messages(ddl);
3106779a307SDongwon Kim 
311142ca628SMarc-André Lureau     width = qemu_dmabuf_get_width(dmabuf);
312f43bf0a7SMarc-André Lureau     height = qemu_dmabuf_get_height(dmabuf);
313f43bf0a7SMarc-André Lureau     stride = qemu_dmabuf_get_stride(dmabuf);
314142ca628SMarc-André Lureau     fourcc = qemu_dmabuf_get_fourcc(dmabuf);
31548dddba1SMarc-André Lureau     modifier = qemu_dmabuf_get_modifier(dmabuf);
31648dddba1SMarc-André Lureau     y0_top = qemu_dmabuf_get_y0_top(dmabuf);
31748dddba1SMarc-André Lureau 
31848dddba1SMarc-André Lureau     /* FIXME: add missing x/y/w/h support */
31948dddba1SMarc-André Lureau     qemu_dbus_display1_listener_call_scanout_dmabuf(
32048dddba1SMarc-André Lureau         ddl->proxy, g_variant_new_handle(0),
32148dddba1SMarc-André Lureau         width, height, stride, fourcc, modifier,
322de1f8ce0SMarc-André Lureau         y0_top, G_DBUS_CALL_FLAGS_NONE,
32348dddba1SMarc-André Lureau         -1, fd_list, NULL, NULL, NULL);
32448dddba1SMarc-André Lureau }
32548dddba1SMarc-André Lureau #endif /* GBM */
32648dddba1SMarc-André Lureau #endif /* OPENGL */
32748dddba1SMarc-André Lureau 
32848dddba1SMarc-André Lureau #ifdef WIN32
dbus_scanout_map(DBusDisplayListener * ddl)32948dddba1SMarc-André Lureau static bool dbus_scanout_map(DBusDisplayListener *ddl)
33048dddba1SMarc-André Lureau {
33148dddba1SMarc-André Lureau     g_autoptr(GError) err = NULL;
33248dddba1SMarc-André Lureau     BOOL success;
33348dddba1SMarc-André Lureau     HANDLE target_handle;
33448dddba1SMarc-André Lureau 
33548dddba1SMarc-André Lureau     if (ddl->ds_share == SHARE_KIND_MAPPED) {
33648dddba1SMarc-André Lureau         return true;
33748dddba1SMarc-André Lureau     }
33848dddba1SMarc-André Lureau 
33948dddba1SMarc-André Lureau     if (!ddl->can_share_map || !ddl->ds->share_handle) {
34048dddba1SMarc-André Lureau         return false;
34148dddba1SMarc-André Lureau     }
34248dddba1SMarc-André Lureau 
34348dddba1SMarc-André Lureau     success = DuplicateHandle(
344*01fff506SMarc-André Lureau         GetCurrentProcess(),
345fa88b85dSMarc-André Lureau         ddl->ds->share_handle,
34648dddba1SMarc-André Lureau         ddl->peer_process,
34748dddba1SMarc-André Lureau         &target_handle,
34848dddba1SMarc-André Lureau         FILE_MAP_READ | SECTION_QUERY,
34948dddba1SMarc-André Lureau         FALSE, 0);
35048dddba1SMarc-André Lureau     if (!success) {
35148dddba1SMarc-André Lureau         g_autofree char *msg = g_win32_error_message(GetLastError());
35248dddba1SMarc-André Lureau         g_debug("Failed to DuplicateHandle: %s", msg);
35348dddba1SMarc-André Lureau         ddl->can_share_map = false;
35448dddba1SMarc-André Lureau         return false;
35548dddba1SMarc-André Lureau     }
35648dddba1SMarc-André Lureau 
35748dddba1SMarc-André Lureau     ddl_discard_display_messages(ddl);
35848dddba1SMarc-André Lureau 
35948dddba1SMarc-André Lureau     if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
36048dddba1SMarc-André Lureau             ddl->map_proxy,
36148dddba1SMarc-André Lureau             GPOINTER_TO_UINT(target_handle),
36248dddba1SMarc-André Lureau             ddl->ds->share_handle_offset,
363de1f8ce0SMarc-André Lureau             surface_width(ddl->ds),
364de1f8ce0SMarc-André Lureau             surface_height(ddl->ds),
365de1f8ce0SMarc-André Lureau             surface_stride(ddl->ds),
366de1f8ce0SMarc-André Lureau             surface_format(ddl->ds),
367de1f8ce0SMarc-André Lureau             G_DBUS_CALL_FLAGS_NONE,
368866b24e4SMarc-Andre Lureau             DBUS_DEFAULT_TIMEOUT,
369de1f8ce0SMarc-André Lureau             NULL,
370de1f8ce0SMarc-André Lureau             &err)) {
371de1f8ce0SMarc-André Lureau         g_debug("Failed to call ScanoutMap: %s", err->message);
372de1f8ce0SMarc-André Lureau         ddl->can_share_map = false;
373de1f8ce0SMarc-André Lureau         return false;
374de1f8ce0SMarc-André Lureau     }
375de1f8ce0SMarc-André Lureau 
376de1f8ce0SMarc-André Lureau     ddl->ds_share = SHARE_KIND_MAPPED;
377de1f8ce0SMarc-André Lureau 
378de1f8ce0SMarc-André Lureau     return true;
379de1f8ce0SMarc-André Lureau }
380de1f8ce0SMarc-André Lureau 
381de1f8ce0SMarc-André Lureau #ifdef CONFIG_OPENGL
382de1f8ce0SMarc-André Lureau 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)383de1f8ce0SMarc-André Lureau dbus_scanout_share_d3d_texture(
384de1f8ce0SMarc-André Lureau     DBusDisplayListener *ddl,
385de1f8ce0SMarc-André Lureau     ID3D11Texture2D *tex,
386de1f8ce0SMarc-André Lureau     bool backing_y_0_top,
387de1f8ce0SMarc-André Lureau     uint32_t backing_width,
388de1f8ce0SMarc-André Lureau     uint32_t backing_height,
389de1f8ce0SMarc-André Lureau     uint32_t x, uint32_t y,
390de1f8ce0SMarc-André Lureau     uint32_t w, uint32_t h)
391de1f8ce0SMarc-André Lureau {
392de1f8ce0SMarc-André Lureau     Error *err = NULL;
393de1f8ce0SMarc-André Lureau     BOOL success;
394de1f8ce0SMarc-André Lureau     HANDLE share_handle, target_handle;
395de1f8ce0SMarc-André Lureau 
396de1f8ce0SMarc-André Lureau     if (!d3d_texture2d_release0(tex, &err)) {
397de1f8ce0SMarc-André Lureau         error_report_err(err);
398de1f8ce0SMarc-André Lureau         return false;
399de1f8ce0SMarc-André Lureau     }
400de1f8ce0SMarc-André Lureau 
401de1f8ce0SMarc-André Lureau     if (!d3d_texture2d_share(tex, &share_handle, &err)) {
402de1f8ce0SMarc-André Lureau         error_report_err(err);
403de1f8ce0SMarc-André Lureau         return false;
404de1f8ce0SMarc-André Lureau     }
405de1f8ce0SMarc-André Lureau 
406de1f8ce0SMarc-André Lureau     success = DuplicateHandle(
407*01fff506SMarc-André Lureau         GetCurrentProcess(),
408fa88b85dSMarc-André Lureau         share_handle,
409de1f8ce0SMarc-André Lureau         ddl->peer_process,
410de1f8ce0SMarc-André Lureau         &target_handle,
411de1f8ce0SMarc-André Lureau         0,
412de1f8ce0SMarc-André Lureau         FALSE, DUPLICATE_SAME_ACCESS);
413de1f8ce0SMarc-André Lureau     if (!success) {
414de1f8ce0SMarc-André Lureau         g_autofree char *msg = g_win32_error_message(GetLastError());
415de1f8ce0SMarc-André Lureau         g_debug("Failed to DuplicateHandle: %s", msg);
416de1f8ce0SMarc-André Lureau         CloseHandle(share_handle);
417de1f8ce0SMarc-André Lureau         return false;
418de1f8ce0SMarc-André Lureau     }
419de1f8ce0SMarc-André Lureau 
420de1f8ce0SMarc-André Lureau     ddl_discard_display_messages(ddl);
421de1f8ce0SMarc-André Lureau 
422de1f8ce0SMarc-André Lureau     qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
423de1f8ce0SMarc-André Lureau         ddl->d3d11_proxy,
424de1f8ce0SMarc-André Lureau         GPOINTER_TO_INT(target_handle),
425de1f8ce0SMarc-André Lureau         backing_width,
426de1f8ce0SMarc-André Lureau         backing_height,
427de1f8ce0SMarc-André Lureau         backing_y_0_top,
428de1f8ce0SMarc-André Lureau         x, y, w, h,
42948dddba1SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
43048dddba1SMarc-André Lureau         -1,
43148dddba1SMarc-André Lureau         NULL, NULL, NULL);
432866b24e4SMarc-Andre Lureau 
433866b24e4SMarc-Andre Lureau     CloseHandle(share_handle);
43448dddba1SMarc-André Lureau 
435f43bf0a7SMarc-André Lureau     if (!d3d_texture2d_acquire0(tex, &err)) {
436142ca628SMarc-André Lureau         error_report_err(err);
437142ca628SMarc-André Lureau         return false;
438142ca628SMarc-André Lureau     }
439142ca628SMarc-André Lureau 
440142ca628SMarc-André Lureau     ddl->d3d_texture = tex;
441142ca628SMarc-André Lureau     ddl->ds_share = SHARE_KIND_D3DTEX;
442bf41ab61SMarc-André Lureau 
443bf41ab61SMarc-André Lureau     return true;
444142ca628SMarc-André Lureau }
445cf283fb4SMarc-André Lureau #endif /* CONFIG_OPENGL */
446cf283fb4SMarc-André Lureau #else /* !WIN32 */
dbus_scanout_map(DBusDisplayListener * ddl)447f43bf0a7SMarc-André Lureau static bool dbus_scanout_map(DBusDisplayListener *ddl)
448c0fcd633SDongwon Kim {
449c0fcd633SDongwon Kim     g_autoptr(GError) err = NULL;
450c0fcd633SDongwon Kim     g_autoptr(GUnixFDList) fd_list = NULL;
451c0fcd633SDongwon Kim 
452142ca628SMarc-André Lureau     if (ddl->ds_share == SHARE_KIND_MAPPED) {
453142ca628SMarc-André Lureau         return true;
454c0fcd633SDongwon Kim     }
455c0fcd633SDongwon Kim 
456c0fcd633SDongwon Kim     if (!ddl->can_share_map || ddl->ds->share_handle == SHAREABLE_NONE) {
457142ca628SMarc-André Lureau         return false;
458142ca628SMarc-André Lureau     }
459142ca628SMarc-André Lureau 
460c0fcd633SDongwon Kim     ddl_discard_display_messages(ddl);
461c0fcd633SDongwon Kim     fd_list = g_unix_fd_list_new();
462c0fcd633SDongwon Kim     if (g_unix_fd_list_append(fd_list, ddl->ds->share_handle, &err) != 0) {
463142ca628SMarc-André Lureau         g_debug("Failed to setup scanout map fdlist: %s", err->message);
464c0fcd633SDongwon Kim         ddl->can_share_map = false;
465c0fcd633SDongwon Kim         return false;
466f43bf0a7SMarc-André Lureau     }
467f43bf0a7SMarc-André Lureau 
468f43bf0a7SMarc-André Lureau     if (!qemu_dbus_display1_listener_unix_map_call_scanout_map_sync(
469f43bf0a7SMarc-André Lureau             ddl->map_proxy,
470f43bf0a7SMarc-André Lureau             g_variant_new_handle(0),
471f43bf0a7SMarc-André Lureau             ddl->ds->share_handle_offset,
472f43bf0a7SMarc-André Lureau             surface_width(ddl->ds),
473f43bf0a7SMarc-André Lureau             surface_height(ddl->ds),
474de1f8ce0SMarc-André Lureau             surface_stride(ddl->ds),
475de1f8ce0SMarc-André Lureau             surface_format(ddl->ds),
476de1f8ce0SMarc-André Lureau             G_DBUS_CALL_FLAGS_NONE,
477de1f8ce0SMarc-André Lureau             DBUS_DEFAULT_TIMEOUT,
478de1f8ce0SMarc-André Lureau             fd_list,
479de1f8ce0SMarc-André Lureau             NULL,
480f43bf0a7SMarc-André Lureau             NULL,
481de1f8ce0SMarc-André Lureau             &err)) {
482f43bf0a7SMarc-André Lureau         g_debug("Failed to call ScanoutMap: %s", err->message);
483142ca628SMarc-André Lureau         ddl->can_share_map = false;
484142ca628SMarc-André Lureau         return false;
485f43bf0a7SMarc-André Lureau     }
486142ca628SMarc-André Lureau 
487142ca628SMarc-André Lureau     ddl->ds_share = SHARE_KIND_MAPPED;
488142ca628SMarc-André Lureau 
489142ca628SMarc-André Lureau     return true;
490142ca628SMarc-André Lureau }
491142ca628SMarc-André Lureau #endif /* WIN32 */
492142ca628SMarc-André Lureau 
4938bb6af67SMarc-André Lureau #ifdef CONFIG_OPENGL
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,void * d3d_tex2d)4946779a307SDongwon Kim static void dbus_scanout_texture(DisplayChangeListener *dcl,
495142ca628SMarc-André Lureau                                  uint32_t tex_id,
496142ca628SMarc-André Lureau                                  bool backing_y_0_top,
497142ca628SMarc-André Lureau                                  uint32_t backing_width,
498142ca628SMarc-André Lureau                                  uint32_t backing_height,
499142ca628SMarc-André Lureau                                  uint32_t x, uint32_t y,
500142ca628SMarc-André Lureau                                  uint32_t w, uint32_t h,
501142ca628SMarc-André Lureau                                  void *d3d_tex2d)
502142ca628SMarc-André Lureau {
503142ca628SMarc-André Lureau     trace_dbus_scanout_texture(tex_id, backing_y_0_top,
5046779a307SDongwon Kim                                backing_width, backing_height, x, y, w, h);
5056779a307SDongwon Kim #ifdef CONFIG_GBM
506142ca628SMarc-André Lureau     g_autoptr(QemuDmaBuf) dmabuf = NULL;
507142ca628SMarc-André Lureau     int fd;
5086779a307SDongwon Kim     uint32_t stride, fourcc;
5096779a307SDongwon Kim     uint64_t modifier;
5106779a307SDongwon Kim 
5116779a307SDongwon Kim     assert(tex_id);
5126779a307SDongwon Kim     fd = egl_get_fd_for_texture(tex_id, (EGLint *)&stride, (EGLint *)&fourcc,
5136779a307SDongwon Kim                                 &modifier);
514142ca628SMarc-André Lureau     if (fd < 0) {
515142ca628SMarc-André Lureau         error_report("%s: failed to get fd for texture", __func__);
516142ca628SMarc-André Lureau         return;
517142ca628SMarc-André Lureau     }
518142ca628SMarc-André Lureau     dmabuf = qemu_dmabuf_new(w, h, stride, x, y, backing_width,
519142ca628SMarc-André Lureau                              backing_height, fourcc, modifier, fd,
520142ca628SMarc-André Lureau                              false, backing_y_0_top);
521142ca628SMarc-André Lureau 
522142ca628SMarc-André Lureau     dbus_scanout_dmabuf(dcl, dmabuf);
523142ca628SMarc-André Lureau     qemu_dmabuf_close(dmabuf);
524142ca628SMarc-André Lureau #endif
525142ca628SMarc-André Lureau 
526142ca628SMarc-André Lureau #ifdef WIN32
527142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
528142ca628SMarc-André Lureau 
529142ca628SMarc-André Lureau     /* there must be a matching gfx_switch before */
530142ca628SMarc-André Lureau     assert(surface_width(ddl->ds) == w);
531142ca628SMarc-André Lureau     assert(surface_height(ddl->ds) == h);
532142ca628SMarc-André Lureau 
533142ca628SMarc-André Lureau     if (d3d_tex2d) {
534142ca628SMarc-André Lureau         dbus_scanout_share_d3d_texture(ddl, d3d_tex2d, backing_y_0_top,
535142ca628SMarc-André Lureau                                        backing_width, backing_height, x, y, w, h);
536142ca628SMarc-André Lureau     } else {
537f43bf0a7SMarc-André Lureau         dbus_scanout_map(ddl);
538f43bf0a7SMarc-André Lureau         egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
539f43bf0a7SMarc-André Lureau     }
540f43bf0a7SMarc-André Lureau #endif
541f43bf0a7SMarc-André Lureau }
542f43bf0a7SMarc-André Lureau 
543f43bf0a7SMarc-André Lureau #ifdef CONFIG_GBM
dbus_cursor_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf,bool have_hot,uint32_t hot_x,uint32_t hot_y)544f43bf0a7SMarc-André Lureau static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
545142ca628SMarc-André Lureau                                QemuDmaBuf *dmabuf, bool have_hot,
546142ca628SMarc-André Lureau                                uint32_t hot_x, uint32_t hot_y)
547142ca628SMarc-André Lureau {
548142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
549142ca628SMarc-André Lureau     DisplaySurface *ds;
550142ca628SMarc-André Lureau     GVariant *v_data = NULL;
551142ca628SMarc-André Lureau     egl_fb cursor_fb = EGL_FB_INIT;
552142ca628SMarc-André Lureau     uint32_t width, height, texture;
553142ca628SMarc-André Lureau 
554142ca628SMarc-André Lureau     if (!dmabuf) {
555142ca628SMarc-André Lureau         qemu_dbus_display1_listener_call_mouse_set(
556142ca628SMarc-André Lureau             ddl->proxy, 0, 0, false,
557142ca628SMarc-André Lureau             G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
558f43bf0a7SMarc-André Lureau         return;
559142ca628SMarc-André Lureau     }
560142ca628SMarc-André Lureau 
561142ca628SMarc-André Lureau     ddl_discard_cursor_messages(ddl);
562142ca628SMarc-André Lureau 
563142ca628SMarc-André Lureau     egl_dmabuf_import_texture(dmabuf);
564142ca628SMarc-André Lureau     texture = qemu_dmabuf_get_texture(dmabuf);
565142ca628SMarc-André Lureau     if (!texture) {
566142ca628SMarc-André Lureau         return;
567142ca628SMarc-André Lureau     }
568142ca628SMarc-André Lureau 
569142ca628SMarc-André Lureau     width = qemu_dmabuf_get_width(dmabuf);
570142ca628SMarc-André Lureau     height = qemu_dmabuf_get_height(dmabuf);
571949c084aSMarc-André Lureau 
5727007e98cSBilal Elmoussaoui     egl_fb_setup_for_tex(&cursor_fb, width, height, texture, false);
5737007e98cSBilal Elmoussaoui     ds = qemu_create_displaysurface(width, height);
5747007e98cSBilal Elmoussaoui     egl_fb_read(ds, &cursor_fb);
5757007e98cSBilal Elmoussaoui 
5767007e98cSBilal Elmoussaoui     v_data = g_variant_new_from_data(
5777007e98cSBilal Elmoussaoui         G_VARIANT_TYPE("ay"),
5787007e98cSBilal Elmoussaoui         surface_data(ds),
5797007e98cSBilal Elmoussaoui         surface_width(ds) * surface_height(ds) * 4,
580142ca628SMarc-André Lureau         TRUE,
5817007e98cSBilal Elmoussaoui         (GDestroyNotify)qemu_free_displaysurface,
582949c084aSMarc-André Lureau         ds);
583949c084aSMarc-André Lureau     qemu_dbus_display1_listener_call_cursor_define(
584949c084aSMarc-André Lureau         ddl->proxy,
585949c084aSMarc-André Lureau         surface_width(ds),
586949c084aSMarc-André Lureau         surface_height(ds),
587949c084aSMarc-André Lureau         hot_x,
588949c084aSMarc-André Lureau         hot_y,
589142ca628SMarc-André Lureau         v_data,
590f43bf0a7SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
591142ca628SMarc-André Lureau         -1,
592142ca628SMarc-André Lureau         NULL,
593142ca628SMarc-André Lureau         NULL,
594142ca628SMarc-André Lureau         NULL);
595142ca628SMarc-André Lureau }
596142ca628SMarc-André Lureau 
dbus_release_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)597f43bf0a7SMarc-André Lureau static void dbus_release_dmabuf(DisplayChangeListener *dcl,
598142ca628SMarc-André Lureau                                 QemuDmaBuf *dmabuf)
599142ca628SMarc-André Lureau {
600142ca628SMarc-André Lureau     dbus_scanout_disable(dcl);
601142ca628SMarc-André Lureau }
602142ca628SMarc-André Lureau #endif /* GBM */
603949c084aSMarc-André Lureau 
dbus_gl_cursor_position(DisplayChangeListener * dcl,uint32_t pos_x,uint32_t pos_y)6047007e98cSBilal Elmoussaoui static void dbus_gl_cursor_position(DisplayChangeListener *dcl,
6057007e98cSBilal Elmoussaoui                                  uint32_t pos_x, uint32_t pos_y)
6067007e98cSBilal Elmoussaoui {
6077007e98cSBilal Elmoussaoui     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
608949c084aSMarc-André Lureau 
609949c084aSMarc-André Lureau     qemu_dbus_display1_listener_call_mouse_set(
610949c084aSMarc-André Lureau         ddl->proxy, pos_x, pos_y, true,
611142ca628SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
61284a0a2efSMarc-André Lureau }
613142ca628SMarc-André Lureau 
dbus_scanout_update(DisplayChangeListener * dcl,uint32_t x,uint32_t y,uint32_t w,uint32_t h)614949c084aSMarc-André Lureau static void dbus_scanout_update(DisplayChangeListener *dcl,
615949c084aSMarc-André Lureau                                 uint32_t x, uint32_t y,
616949c084aSMarc-André Lureau                                 uint32_t w, uint32_t h)
617949c084aSMarc-André Lureau {
618949c084aSMarc-André Lureau     dbus_call_update_gl(dcl, x, y, w, h);
619949c084aSMarc-André Lureau }
620949c084aSMarc-André Lureau 
dbus_gl_refresh(DisplayChangeListener * dcl)621949c084aSMarc-André Lureau static void dbus_gl_refresh(DisplayChangeListener *dcl)
622949c084aSMarc-André Lureau {
623949c084aSMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
624949c084aSMarc-André Lureau 
625949c084aSMarc-André Lureau     graphic_hw_update(dcl->con);
626949c084aSMarc-André Lureau 
627949c084aSMarc-André Lureau     if (!ddl->ds || qemu_console_is_gl_blocked(ddl->dcl.con)) {
628949c084aSMarc-André Lureau         return;
629949c084aSMarc-André Lureau     }
630949c084aSMarc-André Lureau 
631949c084aSMarc-André Lureau #ifdef CONFIG_PIXMAN
632949c084aSMarc-André Lureau     int n_rects = pixman_region32_n_rects(&ddl->gl_damage);
633949c084aSMarc-André Lureau 
634949c084aSMarc-André Lureau     for (int i = 0; i < n_rects; i++) {
635949c084aSMarc-André Lureau         pixman_box32_t *box;
636949c084aSMarc-André Lureau         box = pixman_region32_rectangles(&ddl->gl_damage, NULL) + i;
637949c084aSMarc-André Lureau         /* TODO: Add a UpdateList call to send multiple updates at once */
638949c084aSMarc-André Lureau         dbus_call_update_gl(dcl, box->x1, box->y1,
639949c084aSMarc-André Lureau                             box->x2 - box->x1, box->y2 - box->y1);
640949c084aSMarc-André Lureau     }
641949c084aSMarc-André Lureau     pixman_region32_clear(&ddl->gl_damage);
642949c084aSMarc-André Lureau #else
643949c084aSMarc-André Lureau     if (ddl->gl_damage) {
644949c084aSMarc-André Lureau         dbus_call_update_gl(dcl, 0, 0,
645949c084aSMarc-André Lureau                             surface_width(ddl->ds), surface_height(ddl->ds));
646949c084aSMarc-André Lureau         ddl->gl_damage = 0;
647949c084aSMarc-André Lureau     }
648949c084aSMarc-André Lureau #endif
649949c084aSMarc-André Lureau }
650949c084aSMarc-André Lureau #endif /* OPENGL */
651949c084aSMarc-André Lureau 
dbus_refresh(DisplayChangeListener * dcl)652949c084aSMarc-André Lureau static void dbus_refresh(DisplayChangeListener *dcl)
653949c084aSMarc-André Lureau {
654949c084aSMarc-André Lureau     graphic_hw_update(dcl->con);
655949c084aSMarc-André Lureau }
6567945576cSMarc-André Lureau 
6577945576cSMarc-André Lureau #ifdef CONFIG_OPENGL
dbus_gl_gfx_update(DisplayChangeListener * dcl,int x,int y,int w,int h)6587945576cSMarc-André Lureau static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
6597945576cSMarc-André Lureau                                int x, int y, int w, int h)
6607945576cSMarc-André Lureau {
6617945576cSMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
6627945576cSMarc-André Lureau 
6637945576cSMarc-André Lureau #ifdef CONFIG_PIXMAN
6647945576cSMarc-André Lureau     pixman_region32_t rect_region;
665*01fff506SMarc-André Lureau     pixman_region32_init_rect(&rect_region, x, y, w, h);
666fa88b85dSMarc-André Lureau     pixman_region32_union(&ddl->gl_damage, &ddl->gl_damage, &rect_region);
6677945576cSMarc-André Lureau     pixman_region32_fini(&rect_region);
6687945576cSMarc-André Lureau #else
6697945576cSMarc-André Lureau     ddl->gl_damage++;
6707945576cSMarc-André Lureau #endif
6717945576cSMarc-André Lureau }
6727945576cSMarc-André Lureau #endif
6737945576cSMarc-André Lureau 
dbus_gfx_update_sub(DBusDisplayListener * ddl,int x,int y,int w,int h)674142ca628SMarc-André Lureau static void dbus_gfx_update_sub(DBusDisplayListener *ddl,
675142ca628SMarc-André Lureau                                 int x, int y, int w, int h)
676142ca628SMarc-André Lureau {
677142ca628SMarc-André Lureau     pixman_image_t *img;
678142ca628SMarc-André Lureau     size_t stride;
679142ca628SMarc-André Lureau     GVariant *v_data;
680142ca628SMarc-André Lureau 
681142ca628SMarc-André Lureau     /* make a copy, since gvariant only handles linear data */
682142ca628SMarc-André Lureau     stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
68348dddba1SMarc-André Lureau     img = pixman_image_create_bits(surface_format(ddl->ds),
68448dddba1SMarc-André Lureau                                    w, h, NULL, stride);
68548dddba1SMarc-André Lureau #ifdef CONFIG_PIXMAN
68648dddba1SMarc-André Lureau     pixman_image_composite(PIXMAN_OP_SRC, ddl->ds->image, NULL, img,
68748dddba1SMarc-André Lureau                            x, y, 0, 0, 0, 0, w, h);
68848dddba1SMarc-André Lureau #else
68948dddba1SMarc-André Lureau     {
69048dddba1SMarc-André Lureau         uint8_t *src = (uint8_t *)pixman_image_get_data(ddl->ds->image);
69148dddba1SMarc-André Lureau         uint8_t *dst = (uint8_t *)pixman_image_get_data(img);
69248dddba1SMarc-André Lureau         int bp = PIXMAN_FORMAT_BPP(surface_format(ddl->ds)) / 8;
69348dddba1SMarc-André Lureau         int hh;
6942fa2386eSMarc-André Lureau 
6957945576cSMarc-André Lureau         for (hh = 0; hh < h; hh++) {
6962fa2386eSMarc-André Lureau             memcpy(&dst[stride * hh],
6972fa2386eSMarc-André Lureau                    &src[surface_stride(ddl->ds) * (hh + y) + x * bp],
698949c084aSMarc-André Lureau                    stride);
699142ca628SMarc-André Lureau         }
700142ca628SMarc-André Lureau     }
701f43bf0a7SMarc-André Lureau #endif
702142ca628SMarc-André Lureau     v_data = g_variant_new_from_data(
703142ca628SMarc-André Lureau         G_VARIANT_TYPE("ay"),
704142ca628SMarc-André Lureau         pixman_image_get_data(img),
705142ca628SMarc-André Lureau         pixman_image_get_stride(img) * h,
706142ca628SMarc-André Lureau         TRUE,
707cf283fb4SMarc-André Lureau         (GDestroyNotify)pixman_image_unref,
708cf283fb4SMarc-André Lureau         img);
709142ca628SMarc-André Lureau     qemu_dbus_display1_listener_call_update(ddl->proxy,
710de1f8ce0SMarc-André Lureau         x, y, w, h, pixman_image_get_stride(img), pixman_image_get_format(img),
711142ca628SMarc-André Lureau         v_data,
712142ca628SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
713142ca628SMarc-André Lureau         DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
714142ca628SMarc-André Lureau }
715142ca628SMarc-André Lureau 
ddl_scanout(DBusDisplayListener * ddl)716142ca628SMarc-André Lureau static void ddl_scanout(DBusDisplayListener *ddl)
717bf41ab61SMarc-André Lureau {
718142ca628SMarc-André Lureau     GVariant *v_data;
719142ca628SMarc-André Lureau 
72084a0a2efSMarc-André Lureau     v_data = g_variant_new_from_data(
721142ca628SMarc-André Lureau         G_VARIANT_TYPE("ay"), surface_data(ddl->ds),
722142ca628SMarc-André Lureau         surface_stride(ddl->ds) * surface_height(ddl->ds), TRUE,
723142ca628SMarc-André Lureau         (GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image));
724142ca628SMarc-André Lureau 
725142ca628SMarc-André Lureau     ddl_discard_display_messages(ddl);
726142ca628SMarc-André Lureau 
727142ca628SMarc-André Lureau     qemu_dbus_display1_listener_call_scanout(
728de1f8ce0SMarc-André Lureau         ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds),
729142ca628SMarc-André Lureau         surface_stride(ddl->ds), surface_format(ddl->ds), v_data,
730142ca628SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE, DBUS_DEFAULT_TIMEOUT, NULL, NULL,
731142ca628SMarc-André Lureau         g_object_ref(ddl));
732a418e7aeSAkihiko Odaki }
733142ca628SMarc-André Lureau 
dbus_gfx_update(DisplayChangeListener * dcl,int x,int y,int w,int h)734142ca628SMarc-André Lureau static void dbus_gfx_update(DisplayChangeListener *dcl,
735142ca628SMarc-André Lureau                             int x, int y, int w, int h)
736142ca628SMarc-André Lureau {
737142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
738142ca628SMarc-André Lureau 
739142ca628SMarc-André Lureau     assert(ddl->ds);
740142ca628SMarc-André Lureau 
741142ca628SMarc-André Lureau     trace_dbus_update(x, y, w, h);
742142ca628SMarc-André Lureau 
743142ca628SMarc-André Lureau     if (dbus_scanout_map(ddl)) {
744142ca628SMarc-André Lureau #ifdef WIN32
745142ca628SMarc-André Lureau         qemu_dbus_display1_listener_win32_map_call_update_map(
746142ca628SMarc-André Lureau             ddl->map_proxy,
747142ca628SMarc-André Lureau             x, y, w, h,
748142ca628SMarc-André Lureau             G_DBUS_CALL_FLAGS_NONE,
749142ca628SMarc-André Lureau             DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
750142ca628SMarc-André Lureau #else
751f4579e28SMarc-André Lureau         qemu_dbus_display1_listener_unix_map_call_update_map(
7522512a026SMarc-André Lureau             ddl->map_proxy,
753142ca628SMarc-André Lureau             x, y, w, h,
754142ca628SMarc-André Lureau             G_DBUS_CALL_FLAGS_NONE,
755142ca628SMarc-André Lureau             DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
756142ca628SMarc-André Lureau #endif
757142ca628SMarc-André Lureau         return;
758142ca628SMarc-André Lureau     }
759142ca628SMarc-André Lureau 
760142ca628SMarc-André Lureau     if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
761142ca628SMarc-André Lureau         return ddl_scanout(ddl);
762142ca628SMarc-André Lureau     }
763142ca628SMarc-André Lureau 
764142ca628SMarc-André Lureau     dbus_gfx_update_sub(ddl, x, y, w, h);
765142ca628SMarc-André Lureau }
766142ca628SMarc-André Lureau 
767142ca628SMarc-André Lureau #ifdef CONFIG_OPENGL
dbus_gl_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface)768f43bf0a7SMarc-André Lureau static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
769142ca628SMarc-André Lureau                                struct DisplaySurface *new_surface)
770142ca628SMarc-André Lureau {
771142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
772142ca628SMarc-André Lureau 
773142ca628SMarc-André Lureau     trace_dbus_gl_gfx_switch(new_surface);
774142ca628SMarc-André Lureau 
775142ca628SMarc-André Lureau     ddl->ds = new_surface;
776142ca628SMarc-André Lureau     ddl->ds_share = SHARE_KIND_NONE;
777142ca628SMarc-André Lureau     if (ddl->ds) {
778142ca628SMarc-André Lureau         int width = surface_width(ddl->ds);
779142ca628SMarc-André Lureau         int height = surface_height(ddl->ds);
780f43bf0a7SMarc-André Lureau 
781142ca628SMarc-André Lureau         /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
782142ca628SMarc-André Lureau         dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false,
783142ca628SMarc-André Lureau                              width, height, 0, 0, width, height, NULL);
784f43bf0a7SMarc-André Lureau     }
785f43bf0a7SMarc-André Lureau }
786142ca628SMarc-André Lureau #endif
787142ca628SMarc-André Lureau 
dbus_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface)78884a0a2efSMarc-André Lureau static void dbus_gfx_switch(DisplayChangeListener *dcl,
789142ca628SMarc-André Lureau                             struct DisplaySurface *new_surface)
790142ca628SMarc-André Lureau {
791142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
792142ca628SMarc-André Lureau 
793142ca628SMarc-André Lureau     ddl->ds = new_surface;
794142ca628SMarc-André Lureau     ddl->ds_share = SHARE_KIND_NONE;
795142ca628SMarc-André Lureau }
796142ca628SMarc-André Lureau 
dbus_mouse_set(DisplayChangeListener * dcl,int x,int y,bool on)797142ca628SMarc-André Lureau static void dbus_mouse_set(DisplayChangeListener *dcl,
798142ca628SMarc-André Lureau                            int x, int y, bool on)
799142ca628SMarc-André Lureau {
800142ca628SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
801142ca628SMarc-André Lureau 
802142ca628SMarc-André Lureau     qemu_dbus_display1_listener_call_mouse_set(
803142ca628SMarc-André Lureau         ddl->proxy, x, y, on, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
804142ca628SMarc-André Lureau }
805142ca628SMarc-André Lureau 
dbus_cursor_define(DisplayChangeListener * dcl,QEMUCursor * c)806142ca628SMarc-André Lureau static void dbus_cursor_define(DisplayChangeListener *dcl,
807142ca628SMarc-André Lureau                                QEMUCursor *c)
80848dddba1SMarc-André Lureau {
80948dddba1SMarc-André Lureau     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
810de1f8ce0SMarc-André Lureau     GVariant *v_data = NULL;
81148dddba1SMarc-André Lureau 
812949c084aSMarc-André Lureau     ddl_discard_cursor_messages(ddl);
8137007e98cSBilal Elmoussaoui 
814949c084aSMarc-André Lureau     v_data = g_variant_new_from_data(
815949c084aSMarc-André Lureau         G_VARIANT_TYPE("ay"),
816f43bf0a7SMarc-André Lureau         c->data,
817f43bf0a7SMarc-André Lureau         c->width * c->height * 4,
81848dddba1SMarc-André Lureau         TRUE,
819142ca628SMarc-André Lureau         (GDestroyNotify)cursor_unref,
820142ca628SMarc-André Lureau         cursor_ref(c));
821142ca628SMarc-André Lureau 
822142ca628SMarc-André Lureau     qemu_dbus_display1_listener_call_cursor_define(
823142ca628SMarc-André Lureau         ddl->proxy,
824142ca628SMarc-André Lureau         c->width,
825142ca628SMarc-André Lureau         c->height,
826142ca628SMarc-André Lureau         c->hot_x,
827142ca628SMarc-André Lureau         c->hot_y,
82884a0a2efSMarc-André Lureau         v_data,
829f43bf0a7SMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
830142ca628SMarc-André Lureau         -1,
831142ca628SMarc-André Lureau         NULL,
832142ca628SMarc-André Lureau         NULL,
83384a0a2efSMarc-André Lureau         NULL);
834142ca628SMarc-André Lureau }
835142ca628SMarc-André Lureau 
836142ca628SMarc-André Lureau #ifdef CONFIG_OPENGL
837142ca628SMarc-André Lureau const DisplayChangeListenerOps dbus_gl_dcl_ops = {
838142ca628SMarc-André Lureau     .dpy_name                = "dbus-gl",
839142ca628SMarc-André Lureau     .dpy_gfx_update          = dbus_gl_gfx_update,
840142ca628SMarc-André Lureau     .dpy_gfx_switch          = dbus_gl_gfx_switch,
841142ca628SMarc-André Lureau     .dpy_gfx_check_format    = console_gl_check_format,
842142ca628SMarc-André Lureau     .dpy_refresh             = dbus_gl_refresh,
843142ca628SMarc-André Lureau     .dpy_mouse_set           = dbus_mouse_set,
844142ca628SMarc-André Lureau     .dpy_cursor_define       = dbus_cursor_define,
845142ca628SMarc-André Lureau 
846142ca628SMarc-André Lureau     .dpy_gl_scanout_disable  = dbus_scanout_disable,
847142ca628SMarc-André Lureau     .dpy_gl_scanout_texture  = dbus_scanout_texture,
848142ca628SMarc-André Lureau #ifdef CONFIG_GBM
849142ca628SMarc-André Lureau     .dpy_gl_scanout_dmabuf   = dbus_scanout_dmabuf,
850949c084aSMarc-André Lureau     .dpy_gl_cursor_dmabuf    = dbus_cursor_dmabuf,
8517007e98cSBilal Elmoussaoui     .dpy_gl_release_dmabuf   = dbus_release_dmabuf,
8527007e98cSBilal Elmoussaoui #endif
853142ca628SMarc-André Lureau     .dpy_gl_cursor_position  = dbus_gl_cursor_position,
854142ca628SMarc-André Lureau     .dpy_gl_update           = dbus_scanout_update,
855142ca628SMarc-André Lureau };
856142ca628SMarc-André Lureau #endif
857142ca628SMarc-André Lureau 
85899997823SMarc-André Lureau const DisplayChangeListenerOps dbus_dcl_ops = {
859142ca628SMarc-André Lureau     .dpy_name                = "dbus",
860142ca628SMarc-André Lureau     .dpy_gfx_update          = dbus_gfx_update,
861142ca628SMarc-André Lureau     .dpy_gfx_switch          = dbus_gfx_switch,
862142ca628SMarc-André Lureau     .dpy_refresh             = dbus_refresh,
863142ca628SMarc-André Lureau     .dpy_mouse_set           = dbus_mouse_set,
864142ca628SMarc-André Lureau     .dpy_cursor_define       = dbus_cursor_define,
865142ca628SMarc-André Lureau };
866142ca628SMarc-André Lureau 
86748dddba1SMarc-André Lureau static void
dbus_display_listener_dispose(GObject * object)86848dddba1SMarc-André Lureau dbus_display_listener_dispose(GObject *object)
86948dddba1SMarc-André Lureau {
87048dddba1SMarc-André Lureau     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
87148dddba1SMarc-André Lureau 
87248dddba1SMarc-André Lureau     unregister_displaychangelistener(&ddl->dcl);
87348dddba1SMarc-André Lureau     g_clear_object(&ddl->conn);
87448dddba1SMarc-André Lureau     g_clear_pointer(&ddl->bus_name, g_free);
87548dddba1SMarc-André Lureau     g_clear_object(&ddl->proxy);
87648dddba1SMarc-André Lureau #ifdef WIN32
87748dddba1SMarc-André Lureau     g_clear_object(&ddl->map_proxy);
87848dddba1SMarc-André Lureau     g_clear_object(&ddl->d3d11_proxy);
87948dddba1SMarc-André Lureau     g_clear_pointer(&ddl->peer_process, CloseHandle);
88048dddba1SMarc-André Lureau #ifdef CONFIG_PIXMAN
88148dddba1SMarc-André Lureau     pixman_region32_fini(&ddl->gl_damage);
882de1f8ce0SMarc-André Lureau #endif
883de1f8ce0SMarc-André Lureau #ifdef CONFIG_OPENGL
88448dddba1SMarc-André Lureau     egl_fb_destroy(&ddl->fb);
88548dddba1SMarc-André Lureau #endif
88648dddba1SMarc-André Lureau #endif
88748dddba1SMarc-André Lureau 
88848dddba1SMarc-André Lureau     G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
88948dddba1SMarc-André Lureau }
89048dddba1SMarc-André Lureau 
89148dddba1SMarc-André Lureau static void
dbus_display_listener_constructed(GObject * object)892de1f8ce0SMarc-André Lureau dbus_display_listener_constructed(GObject *object)
893de1f8ce0SMarc-André Lureau {
89448dddba1SMarc-André Lureau     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
89548dddba1SMarc-André Lureau 
89648dddba1SMarc-André Lureau     ddl->dcl.ops = &dbus_dcl_ops;
89748dddba1SMarc-André Lureau #ifdef CONFIG_OPENGL
89848dddba1SMarc-André Lureau     if (display_opengl) {
89948dddba1SMarc-André Lureau         ddl->dcl.ops = &dbus_gl_dcl_ops;
900de1f8ce0SMarc-André Lureau     }
90148dddba1SMarc-André Lureau #endif
90248dddba1SMarc-André Lureau 
90348dddba1SMarc-André Lureau     G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object);
90448dddba1SMarc-André Lureau }
90548dddba1SMarc-André Lureau 
90648dddba1SMarc-André Lureau static void
dbus_display_listener_class_init(DBusDisplayListenerClass * klass)90748dddba1SMarc-André Lureau dbus_display_listener_class_init(DBusDisplayListenerClass *klass)
908de1f8ce0SMarc-André Lureau {
90948dddba1SMarc-André Lureau     GObjectClass *object_class = G_OBJECT_CLASS(klass);
91048dddba1SMarc-André Lureau 
91148dddba1SMarc-André Lureau     object_class->dispose = dbus_display_listener_dispose;
91248dddba1SMarc-André Lureau     object_class->constructed = dbus_display_listener_constructed;
91348dddba1SMarc-André Lureau }
91448dddba1SMarc-André Lureau 
915de1f8ce0SMarc-André Lureau static void
dbus_display_listener_init(DBusDisplayListener * ddl)91648dddba1SMarc-André Lureau dbus_display_listener_init(DBusDisplayListener *ddl)
91748dddba1SMarc-André Lureau {
91848dddba1SMarc-André Lureau #ifdef CONFIG_PIXMAN
91948dddba1SMarc-André Lureau     pixman_region32_init(&ddl->gl_damage);
92048dddba1SMarc-André Lureau #endif
92148dddba1SMarc-André Lureau }
92248dddba1SMarc-André Lureau 
92348dddba1SMarc-André Lureau const char *
dbus_display_listener_get_bus_name(DBusDisplayListener * ddl)92448dddba1SMarc-André Lureau dbus_display_listener_get_bus_name(DBusDisplayListener *ddl)
925de1f8ce0SMarc-André Lureau {
926de1f8ce0SMarc-André Lureau     return ddl->bus_name ?: "p2p";
927de1f8ce0SMarc-André Lureau }
928de1f8ce0SMarc-André Lureau 
929de1f8ce0SMarc-André Lureau DBusDisplayConsole *
dbus_display_listener_get_console(DBusDisplayListener * ddl)930de1f8ce0SMarc-André Lureau dbus_display_listener_get_console(DBusDisplayListener *ddl)
931de1f8ce0SMarc-André Lureau {
932de1f8ce0SMarc-André Lureau     return ddl->console;
933de1f8ce0SMarc-André Lureau }
934de1f8ce0SMarc-André Lureau 
935de1f8ce0SMarc-André Lureau static bool
dbus_display_listener_implements(DBusDisplayListener * ddl,const char * iface)936de1f8ce0SMarc-André Lureau dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
937de1f8ce0SMarc-André Lureau {
938de1f8ce0SMarc-André Lureau     QemuDBusDisplay1Listener *l = QEMU_DBUS_DISPLAY1_LISTENER(ddl->proxy);
939de1f8ce0SMarc-André Lureau     bool implements;
940de1f8ce0SMarc-André Lureau 
941de1f8ce0SMarc-André Lureau     implements = g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l), iface);
942de1f8ce0SMarc-André Lureau     if (!implements) {
943de1f8ce0SMarc-André Lureau         g_debug("Display listener does not implement: `%s`", iface);
944de1f8ce0SMarc-André Lureau     }
945de1f8ce0SMarc-André Lureau 
946de1f8ce0SMarc-André Lureau     return implements;
947de1f8ce0SMarc-André Lureau }
948de1f8ce0SMarc-André Lureau 
949de1f8ce0SMarc-André Lureau #ifdef WIN32
950de1f8ce0SMarc-André Lureau static bool
dbus_display_listener_setup_peer_process(DBusDisplayListener * ddl)951de1f8ce0SMarc-André Lureau dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
952de1f8ce0SMarc-André Lureau {
953de1f8ce0SMarc-André Lureau     g_autoptr(GError) err = NULL;
954de1f8ce0SMarc-André Lureau     GDBusConnection *conn;
955de1f8ce0SMarc-André Lureau     GIOStream *stream;
956de1f8ce0SMarc-André Lureau     GSocket *sock;
957de1f8ce0SMarc-André Lureau     g_autoptr(GCredentials) creds = NULL;
958de1f8ce0SMarc-André Lureau     DWORD *pid;
959de1f8ce0SMarc-André Lureau 
960de1f8ce0SMarc-André Lureau     if (ddl->peer_process) {
961de1f8ce0SMarc-André Lureau         return true;
962de1f8ce0SMarc-André Lureau     }
963de1f8ce0SMarc-André Lureau 
964de1f8ce0SMarc-André Lureau     conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy));
965de1f8ce0SMarc-André Lureau     stream = g_dbus_connection_get_stream(conn);
966de1f8ce0SMarc-André Lureau 
967de1f8ce0SMarc-André Lureau     if (!G_IS_UNIX_CONNECTION(stream)) {
968de1f8ce0SMarc-André Lureau         return false;
969de1f8ce0SMarc-André Lureau     }
970de1f8ce0SMarc-André Lureau 
971de1f8ce0SMarc-André Lureau     sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream));
97248dddba1SMarc-André Lureau     creds = g_socket_get_credentials(sock, &err);
97348dddba1SMarc-André Lureau 
97448dddba1SMarc-André Lureau     if (!creds) {
97548dddba1SMarc-André Lureau         g_debug("Failed to get peer credentials: %s", err->message);
976de1f8ce0SMarc-André Lureau         return false;
97748dddba1SMarc-André Lureau     }
97848dddba1SMarc-André Lureau 
97948dddba1SMarc-André Lureau     pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID);
98048dddba1SMarc-André Lureau 
98148dddba1SMarc-André Lureau     if (pid == NULL) {
98248dddba1SMarc-André Lureau         g_debug("Failed to get peer PID");
98348dddba1SMarc-André Lureau         return false;
98448dddba1SMarc-André Lureau     }
98548dddba1SMarc-André Lureau 
98648dddba1SMarc-André Lureau     ddl->peer_process = OpenProcess(
98748dddba1SMarc-André Lureau         PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
98848dddba1SMarc-André Lureau         false, *pid);
98948dddba1SMarc-André Lureau 
99048dddba1SMarc-André Lureau     if (!ddl->peer_process) {
991fa88b85dSMarc-André Lureau         g_autofree char *msg = g_win32_error_message(GetLastError());
992fa88b85dSMarc-André Lureau         g_debug("Failed to OpenProcess: %s", msg);
993fa88b85dSMarc-André Lureau         return false;
994fa88b85dSMarc-André Lureau     }
995fa88b85dSMarc-André Lureau 
996fa88b85dSMarc-André Lureau     return true;
997fa88b85dSMarc-André Lureau }
998*01fff506SMarc-André Lureau #endif
999fa88b85dSMarc-André Lureau 
1000fa88b85dSMarc-André Lureau static void
dbus_display_listener_setup_d3d11(DBusDisplayListener * ddl)1001fa88b85dSMarc-André Lureau dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
1002fa88b85dSMarc-André Lureau {
1003fa88b85dSMarc-André Lureau #ifdef WIN32
1004fa88b85dSMarc-André Lureau     g_autoptr(GError) err = NULL;
1005*01fff506SMarc-André Lureau 
1006*01fff506SMarc-André Lureau     if (!dbus_display_listener_implements(ddl,
1007*01fff506SMarc-André Lureau             "org.qemu.Display1.Listener.Win32.D3d11")) {
1008*01fff506SMarc-André Lureau         return;
1009*01fff506SMarc-André Lureau     }
1010*01fff506SMarc-André Lureau 
1011*01fff506SMarc-André Lureau     if (!dbus_display_listener_setup_peer_process(ddl)) {
1012*01fff506SMarc-André Lureau         return;
1013*01fff506SMarc-André Lureau     }
1014*01fff506SMarc-André Lureau 
1015*01fff506SMarc-André Lureau     ddl->d3d11_proxy =
1016*01fff506SMarc-André Lureau         qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl->conn,
1017*01fff506SMarc-André Lureau             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1018*01fff506SMarc-André Lureau             NULL,
1019*01fff506SMarc-André Lureau             "/org/qemu/Display1/Listener",
1020*01fff506SMarc-André Lureau             NULL,
1021*01fff506SMarc-André Lureau             &err);
1022*01fff506SMarc-André Lureau     if (!ddl->d3d11_proxy) {
1023*01fff506SMarc-André Lureau         g_debug("Failed to setup win32 d3d11 proxy: %s", err->message);
10249391f419SMarc-André Lureau         return;
1025fa88b85dSMarc-André Lureau     }
1026fa88b85dSMarc-André Lureau #endif
1027*01fff506SMarc-André Lureau }
1028fa88b85dSMarc-André Lureau 
1029fa88b85dSMarc-André Lureau static void
dbus_display_listener_setup_shared_map(DBusDisplayListener * ddl)1030fa88b85dSMarc-André Lureau dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
1031fa88b85dSMarc-André Lureau {
1032142ca628SMarc-André Lureau     g_autoptr(GError) err = NULL;
1033142ca628SMarc-André Lureau 
1034142ca628SMarc-André Lureau #ifdef WIN32
1035142ca628SMarc-André Lureau     if (!dbus_display_listener_implements(
1036142ca628SMarc-André Lureau             ddl, "org.qemu.Display1.Listener.Win32.Map")) {
1037142ca628SMarc-André Lureau         return;
1038142ca628SMarc-André Lureau     }
1039142ca628SMarc-André Lureau 
1040142ca628SMarc-André Lureau     if (!dbus_display_listener_setup_peer_process(ddl)) {
1041142ca628SMarc-André Lureau         return;
1042142ca628SMarc-André Lureau     }
1043142ca628SMarc-André Lureau 
1044142ca628SMarc-André Lureau     ddl->map_proxy =
1045142ca628SMarc-André Lureau         qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl->conn,
1046142ca628SMarc-André Lureau             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1047142ca628SMarc-André Lureau             NULL,
1048142ca628SMarc-André Lureau             "/org/qemu/Display1/Listener",
1049142ca628SMarc-André Lureau             NULL,
1050142ca628SMarc-André Lureau             &err);
1051142ca628SMarc-André Lureau     if (!ddl->map_proxy) {
1052142ca628SMarc-André Lureau         g_debug("Failed to setup win32 map proxy: %s", err->message);
1053142ca628SMarc-André Lureau         return;
1054142ca628SMarc-André Lureau     }
1055142ca628SMarc-André Lureau 
1056fa88b85dSMarc-André Lureau     ddl->can_share_map = true;
1057142ca628SMarc-André Lureau #else /* !WIN32 */
1058142ca628SMarc-André Lureau     if (!dbus_display_listener_implements(
1059142ca628SMarc-André Lureau             ddl, "org.qemu.Display1.Listener.Unix.Map")) {
1060142ca628SMarc-André Lureau         return;
106148dddba1SMarc-André Lureau     }
1062de1f8ce0SMarc-André Lureau     ddl->map_proxy = qemu_dbus_display1_listener_unix_map_proxy_new_sync(
106348dddba1SMarc-André Lureau         ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
1064142ca628SMarc-André Lureau         "/org/qemu/Display1/Listener", NULL, &err);
1065142ca628SMarc-André Lureau     if (!ddl->map_proxy) {
1066142ca628SMarc-André Lureau         g_debug("Failed to setup Unix map proxy: %s", err->message);
1067142ca628SMarc-André Lureau         return;
1068142ca628SMarc-André Lureau     }
1069142ca628SMarc-André Lureau 
1070142ca628SMarc-André Lureau     ddl->can_share_map = true;
1071 #endif
1072 }
1073 
1074 static GDBusMessage *
dbus_filter(GDBusConnection * connection,GDBusMessage * message,gboolean incoming,gpointer user_data)1075 dbus_filter(GDBusConnection *connection,
1076             GDBusMessage    *message,
1077             gboolean         incoming,
1078             gpointer         user_data)
1079 {
1080     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data);
1081     guint32 serial, discard_serial;
1082 
1083     if (incoming) {
1084         return message;
1085     }
1086 
1087     serial = g_dbus_message_get_serial(message);
1088 
1089     discard_serial = g_atomic_int_get(&ddl->display_serial_to_discard);
1090     if (serial <= discard_serial) {
1091         const char *member = g_dbus_message_get_member(message);
1092         static const char *const display_messages[] = {
1093             "Scanout",
1094             "Update",
1095 #ifdef CONFIG_GBM
1096             "ScanoutDMABUF",
1097             "UpdateDMABUF",
1098 #endif
1099             "ScanoutMap",
1100             "UpdateMap",
1101             "Disable",
1102             NULL,
1103         };
1104 
1105         if (g_strv_contains(display_messages, member)) {
1106             trace_dbus_filter(serial, discard_serial);
1107             g_object_unref(message);
1108             return NULL;
1109         }
1110     }
1111 
1112     discard_serial = g_atomic_int_get(&ddl->cursor_serial_to_discard);
1113     if (serial <= discard_serial) {
1114         const gchar *member = g_dbus_message_get_member(message);
1115         static const char *const cursor_messages[] = {
1116             "CursorDefine",
1117             NULL
1118         };
1119 
1120         if (g_strv_contains(cursor_messages, member)) {
1121             trace_dbus_filter(serial, discard_serial);
1122             g_object_unref(message);
1123             return NULL;
1124         }
1125     }
1126 
1127     return message;
1128 }
1129 
1130 DBusDisplayListener *
dbus_display_listener_new(const char * bus_name,GDBusConnection * conn,DBusDisplayConsole * console)1131 dbus_display_listener_new(const char *bus_name,
1132                           GDBusConnection *conn,
1133                           DBusDisplayConsole *console)
1134 {
1135     DBusDisplayListener *ddl;
1136     QemuConsole *con;
1137     g_autoptr(GError) err = NULL;
1138 
1139     ddl = g_object_new(DBUS_DISPLAY_TYPE_LISTENER, NULL);
1140     ddl->proxy =
1141         qemu_dbus_display1_listener_proxy_new_sync(conn,
1142             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1143             NULL,
1144             "/org/qemu/Display1/Listener",
1145             NULL,
1146             &err);
1147     if (!ddl->proxy) {
1148         error_report("Failed to setup proxy: %s", err->message);
1149         g_object_unref(conn);
1150         g_object_unref(ddl);
1151         return NULL;
1152     }
1153 
1154     ddl->dbus_filter = g_dbus_connection_add_filter(conn, dbus_filter, g_object_ref(ddl), g_object_unref);
1155     ddl->bus_name = g_strdup(bus_name);
1156     ddl->conn = conn;
1157     ddl->console = console;
1158 
1159     dbus_display_listener_setup_shared_map(ddl);
1160     trace_dbus_can_share_map(ddl->can_share_map);
1161     dbus_display_listener_setup_d3d11(ddl);
1162 
1163     con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
1164     assert(con);
1165     ddl->dcl.con = con;
1166     register_displaychangelistener(&ddl->dcl);
1167 
1168     return ddl;
1169 }
1170