xref: /qemu/ui/dbus-listener.c (revision 3e1210e8b0d86a2190e51632985c3da3e5721336)
1 /*
2  * QEMU DBus display console
3  *
4  * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "qemu/osdep.h"
25 #include "qemu/error-report.h"
26 #include "qapi/error.h"
27 #include "system/system.h"
28 #include "dbus.h"
29 #include "glib.h"
30 #ifdef G_OS_UNIX
31 #include <gio/gunixfdlist.h>
32 #endif
33 #ifdef WIN32
34 #include <d3d11.h>
35 #include <dxgi1_2.h>
36 #endif
37 
38 #ifdef CONFIG_OPENGL
39 #include "ui/shader.h"
40 #include "ui/egl-helpers.h"
41 #include "ui/egl-context.h"
42 #include "ui/qemu-pixman.h"
43 #endif
44 #include "trace.h"
45 
46 static void dbus_gfx_switch(DisplayChangeListener *dcl,
47                             struct DisplaySurface *new_surface);
48 
49 enum share_kind {
50     SHARE_KIND_NONE,
51     SHARE_KIND_MAPPED,
52     SHARE_KIND_D3DTEX,
53 };
54 
55 struct _DBusDisplayListener {
56     GObject parent;
57 
58     char *bus_name;
59     DBusDisplayConsole *console;
60     GDBusConnection *conn;
61 
62     QemuDBusDisplay1Listener *proxy;
63 
64 #ifdef CONFIG_PIXMAN
65     /* Keep track of the damage region */
66     pixman_region32_t gl_damage;
67 #else
68     int gl_damage;
69 #endif
70 
71     DisplayChangeListener dcl;
72     DisplaySurface *ds;
73     enum share_kind ds_share;
74 
75     bool ds_mapped;
76     bool can_share_map;
77 
78 #ifdef WIN32
79     QemuDBusDisplay1ListenerWin32Map *map_proxy;
80     QemuDBusDisplay1ListenerWin32D3d11 *d3d11_proxy;
81     HANDLE peer_process;
82     ID3D11Texture2D *d3d_texture;
83 #ifdef CONFIG_OPENGL
84     egl_fb fb;
85 #endif
86 #else /* !WIN32 */
87     QemuDBusDisplay1ListenerUnixMap *map_proxy;
88     QemuDBusDisplay1ListenerUnixScanoutDMABUF2 *scanout_dmabuf_v2_proxy;
89 #endif
90 
91     guint dbus_filter;
92     guint32 display_serial_to_discard;
93     guint32 cursor_serial_to_discard;
94 };
95 
96 G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
97 
98 static void dbus_gfx_update(DisplayChangeListener *dcl,
99                             int x, int y, int w, int h);
100 
ddl_discard_display_messages(DBusDisplayListener * ddl)101 static void ddl_discard_display_messages(DBusDisplayListener *ddl)
102 {
103     guint32 serial = g_dbus_connection_get_last_serial(
104         g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
105 
106     g_atomic_int_set(&ddl->display_serial_to_discard, serial);
107 }
108 
ddl_discard_cursor_messages(DBusDisplayListener * ddl)109 static void ddl_discard_cursor_messages(DBusDisplayListener *ddl)
110 {
111     guint32 serial = g_dbus_connection_get_last_serial(
112         g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
113 
114     g_atomic_int_set(&ddl->cursor_serial_to_discard, serial);
115 }
116 
117 #ifdef CONFIG_OPENGL
dbus_scanout_disable(DisplayChangeListener * dcl)118 static void dbus_scanout_disable(DisplayChangeListener *dcl)
119 {
120     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
121 
122     ddl_discard_display_messages(ddl);
123 
124     qemu_dbus_display1_listener_call_disable(
125         ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
126 }
127 
128 #ifdef WIN32
d3d_texture2d_share(ID3D11Texture2D * d3d_texture,HANDLE * handle,Error ** errp)129 static bool d3d_texture2d_share(ID3D11Texture2D *d3d_texture,
130                                 HANDLE *handle, Error **errp)
131 {
132     IDXGIResource1 *dxgiResource = NULL;
133     HRESULT hr;
134 
135     hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
136                                              &IID_IDXGIResource1,
137                                              (void **)&dxgiResource);
138     if (FAILED(hr)) {
139         goto fail;
140     }
141 
142     hr = dxgiResource->lpVtbl->CreateSharedHandle(
143         dxgiResource,
144         NULL,
145         DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
146         NULL,
147         handle
148         );
149 
150     dxgiResource->lpVtbl->Release(dxgiResource);
151 
152     if (SUCCEEDED(hr)) {
153         return true;
154     }
155 
156 fail:
157     error_setg_win32(errp, GetLastError(), "failed to create shared handle");
158     return false;
159 }
160 
d3d_texture2d_acquire0(ID3D11Texture2D * d3d_texture,Error ** errp)161 static bool d3d_texture2d_acquire0(ID3D11Texture2D *d3d_texture, Error **errp)
162 {
163     IDXGIKeyedMutex *dxgiMutex = NULL;
164     HRESULT hr;
165 
166     hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
167                                              &IID_IDXGIKeyedMutex,
168                                              (void **)&dxgiMutex);
169     if (FAILED(hr)) {
170         goto fail;
171     }
172 
173     hr = dxgiMutex->lpVtbl->AcquireSync(dxgiMutex, 0, INFINITE);
174 
175     dxgiMutex->lpVtbl->Release(dxgiMutex);
176 
177     if (SUCCEEDED(hr)) {
178         return true;
179     }
180 
181 fail:
182     error_setg_win32(errp, GetLastError(), "failed to acquire texture mutex");
183     return false;
184 }
185 
d3d_texture2d_release0(ID3D11Texture2D * d3d_texture,Error ** errp)186 static bool d3d_texture2d_release0(ID3D11Texture2D *d3d_texture, Error **errp)
187 {
188     IDXGIKeyedMutex *dxgiMutex = NULL;
189     HRESULT hr;
190 
191     hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
192                                              &IID_IDXGIKeyedMutex,
193                                              (void **)&dxgiMutex);
194     if (FAILED(hr)) {
195         goto fail;
196     }
197 
198     hr = dxgiMutex->lpVtbl->ReleaseSync(dxgiMutex, 0);
199 
200     dxgiMutex->lpVtbl->Release(dxgiMutex);
201 
202     if (SUCCEEDED(hr)) {
203         return true;
204     }
205 
206 fail:
207     error_setg_win32(errp, GetLastError(), "failed to release texture mutex");
208     return false;
209 }
210 #endif /* WIN32 */
211 
212 #if defined(CONFIG_GBM) || defined(WIN32)
dbus_update_gl_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)213 static void dbus_update_gl_cb(GObject *source_object,
214                               GAsyncResult *res,
215                               gpointer user_data)
216 {
217     g_autoptr(GError) err = NULL;
218     DBusDisplayListener *ddl = user_data;
219     bool success;
220 
221 #ifdef CONFIG_GBM
222     success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
223         ddl->proxy, res, &err);
224 #endif
225 
226 #ifdef WIN32
227     success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
228         ddl->d3d11_proxy, res, &err);
229     d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
230 #endif
231 
232     if (!success) {
233         error_report("Failed to call update: %s", err->message);
234     }
235 
236     graphic_hw_gl_block(ddl->dcl.con, false);
237     g_object_unref(ddl);
238 }
239 #endif
240 
dbus_call_update_gl(DisplayChangeListener * dcl,int x,int y,int w,int h)241 static void dbus_call_update_gl(DisplayChangeListener *dcl,
242                                 int x, int y, int w, int h)
243 {
244 #if defined(CONFIG_GBM) || defined(WIN32)
245     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
246 #endif
247 
248     trace_dbus_update_gl(x, y, w, h);
249 
250     glFlush();
251 #ifdef CONFIG_GBM
252     graphic_hw_gl_block(ddl->dcl.con, true);
253     qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy,
254         x, y, w, h,
255         G_DBUS_CALL_FLAGS_NONE,
256         DBUS_DEFAULT_TIMEOUT, NULL,
257         dbus_update_gl_cb,
258         g_object_ref(ddl));
259 #endif
260 
261 #ifdef WIN32
262     switch (ddl->ds_share) {
263     case SHARE_KIND_MAPPED:
264         egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
265         dbus_gfx_update(dcl, x, y, w, h);
266         break;
267     case SHARE_KIND_D3DTEX: {
268         Error *err = NULL;
269         assert(ddl->d3d_texture);
270 
271         graphic_hw_gl_block(ddl->dcl.con, true);
272         if (!d3d_texture2d_release0(ddl->d3d_texture, &err)) {
273             error_report_err(err);
274             return;
275         }
276         qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
277             ddl->d3d11_proxy,
278             x, y, w, h,
279             G_DBUS_CALL_FLAGS_NONE,
280             DBUS_DEFAULT_TIMEOUT, NULL,
281             dbus_update_gl_cb,
282             g_object_ref(ddl));
283         break;
284     }
285     default:
286         g_warn_if_reached();
287     }
288 #endif
289 }
290 
291 #ifdef CONFIG_GBM
dbus_scanout_dmabuf_v1(DBusDisplayListener * ddl,QemuDmaBuf * dmabuf)292 static void dbus_scanout_dmabuf_v1(DBusDisplayListener *ddl,
293                                    QemuDmaBuf *dmabuf)
294 {
295     g_autoptr(GError) err = NULL;
296     g_autoptr(GUnixFDList) fd_list = NULL;
297     int fd;
298     uint32_t width, height, stride, fourcc;
299     uint64_t modifier;
300     bool y0_top;
301 
302     fd = qemu_dmabuf_get_fds(dmabuf, NULL)[0];
303     fd_list = g_unix_fd_list_new();
304     if (g_unix_fd_list_append(fd_list, fd, &err) != 0) {
305         error_report("Failed to setup dmabuf fdlist: %s", err->message);
306         return;
307     }
308 
309     ddl_discard_display_messages(ddl);
310 
311     width = qemu_dmabuf_get_width(dmabuf);
312     height = qemu_dmabuf_get_height(dmabuf);
313     stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
314     fourcc = qemu_dmabuf_get_fourcc(dmabuf);
315     modifier = qemu_dmabuf_get_modifier(dmabuf);
316     y0_top = qemu_dmabuf_get_y0_top(dmabuf);
317 
318     /* FIXME: add missing x/y/w/h support */
319     qemu_dbus_display1_listener_call_scanout_dmabuf(
320         ddl->proxy, g_variant_new_handle(0),
321         width, height, stride, fourcc, modifier,
322         y0_top, G_DBUS_CALL_FLAGS_NONE,
323         -1, fd_list, NULL, NULL, NULL);
324 }
325 
dbus_scanout_dmabuf_v2(DBusDisplayListener * ddl,QemuDmaBuf * dmabuf)326 static void dbus_scanout_dmabuf_v2(DBusDisplayListener *ddl,
327                                    QemuDmaBuf *dmabuf)
328 {
329     g_autoptr(GError) err = NULL;
330     g_autoptr(GUnixFDList) fd_list = NULL;
331     int i, fd_index[DMABUF_MAX_PLANES], num_fds;
332     uint32_t x, y, width, height, fourcc, backing_width, backing_height;
333     GVariant *fd, *offset, *stride, *fd_handles[DMABUF_MAX_PLANES];
334     uint64_t modifier;
335     bool y0_top;
336     int nfds, noffsets, nstrides;
337     const int *fds = qemu_dmabuf_get_fds(dmabuf, &nfds);
338     const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets);
339     const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides);
340     uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf);
341 
342     assert(nfds >= num_planes);
343     assert(noffsets >= num_planes);
344     assert(nstrides >= num_planes);
345 
346     fd_list = g_unix_fd_list_new();
347 
348     for (num_fds = 0; num_fds < num_planes; num_fds++) {
349         int plane_fd = fds[num_fds];
350 
351         if (plane_fd < 0) {
352             break;
353         }
354 
355         fd_index[num_fds] = g_unix_fd_list_append(fd_list, plane_fd, &err);
356         if (fd_index[num_fds] < 0) {
357             error_report("Failed to setup dmabuf fdlist: %s", err->message);
358             return;
359         }
360     }
361 
362     ddl_discard_display_messages(ddl);
363 
364     x = qemu_dmabuf_get_x(dmabuf);
365     y = qemu_dmabuf_get_y(dmabuf);
366     width = qemu_dmabuf_get_width(dmabuf);
367     height = qemu_dmabuf_get_height(dmabuf);
368     fourcc = qemu_dmabuf_get_fourcc(dmabuf);
369     backing_width = qemu_dmabuf_get_backing_width(dmabuf);
370     backing_height = qemu_dmabuf_get_backing_height(dmabuf);
371     modifier = qemu_dmabuf_get_modifier(dmabuf);
372     y0_top = qemu_dmabuf_get_y0_top(dmabuf);
373 
374     offset = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
375                                        offsets, num_planes, sizeof(uint32_t));
376     stride = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
377                                        strides, num_planes, sizeof(uint32_t));
378 
379     for (i = 0; i < num_fds; i++) {
380         fd_handles[i] = g_variant_new_handle(fd_index[i]);
381     }
382     fd = g_variant_new_array(G_VARIANT_TYPE_HANDLE, fd_handles, num_fds);
383 
384     qemu_dbus_display1_listener_unix_scanout_dmabuf2_call_scanout_dmabuf2(
385         ddl->scanout_dmabuf_v2_proxy, fd, x, y, width, height, offset, stride,
386         num_planes, fourcc, backing_width, backing_height, modifier, y0_top,
387         G_DBUS_CALL_FLAGS_NONE, -1, fd_list, NULL, NULL, NULL);
388 }
389 
dbus_scanout_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)390 static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
391                                 QemuDmaBuf *dmabuf)
392 {
393     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
394 
395     if (ddl->scanout_dmabuf_v2_proxy) {
396         dbus_scanout_dmabuf_v2(ddl, dmabuf);
397     } else {
398         if (qemu_dmabuf_get_num_planes(dmabuf) > 1) {
399             g_debug("org.qemu.Display1.Listener.ScanoutDMABUF "
400                     "does not support mutli plane");
401             return;
402         }
403         dbus_scanout_dmabuf_v1(ddl, dmabuf);
404     }
405 }
406 #endif /* GBM */
407 #endif /* OPENGL */
408 
409 #ifdef WIN32
dbus_scanout_map(DBusDisplayListener * ddl)410 static bool dbus_scanout_map(DBusDisplayListener *ddl)
411 {
412     g_autoptr(GError) err = NULL;
413     BOOL success;
414     HANDLE target_handle;
415 
416     if (ddl->ds_share == SHARE_KIND_MAPPED) {
417         return true;
418     }
419 
420     if (!ddl->can_share_map || !ddl->ds->share_handle) {
421         return false;
422     }
423 
424     success = DuplicateHandle(
425         GetCurrentProcess(),
426         ddl->ds->share_handle,
427         ddl->peer_process,
428         &target_handle,
429         FILE_MAP_READ | SECTION_QUERY,
430         FALSE, 0);
431     if (!success) {
432         g_autofree char *msg = g_win32_error_message(GetLastError());
433         g_debug("Failed to DuplicateHandle: %s", msg);
434         ddl->can_share_map = false;
435         return false;
436     }
437 
438     ddl_discard_display_messages(ddl);
439 
440     if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
441             ddl->map_proxy,
442             GPOINTER_TO_UINT(target_handle),
443             ddl->ds->share_handle_offset,
444             surface_width(ddl->ds),
445             surface_height(ddl->ds),
446             surface_stride(ddl->ds),
447             surface_format(ddl->ds),
448             G_DBUS_CALL_FLAGS_NONE,
449             DBUS_DEFAULT_TIMEOUT,
450             NULL,
451             &err)) {
452         g_debug("Failed to call ScanoutMap: %s", err->message);
453         ddl->can_share_map = false;
454         return false;
455     }
456 
457     ddl->ds_share = SHARE_KIND_MAPPED;
458 
459     return true;
460 }
461 
462 #ifdef CONFIG_OPENGL
463 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)464 dbus_scanout_share_d3d_texture(
465     DBusDisplayListener *ddl,
466     ID3D11Texture2D *tex,
467     bool backing_y_0_top,
468     uint32_t backing_width,
469     uint32_t backing_height,
470     uint32_t x, uint32_t y,
471     uint32_t w, uint32_t h)
472 {
473     Error *err = NULL;
474     BOOL success;
475     HANDLE share_handle, target_handle;
476 
477     if (!d3d_texture2d_release0(tex, &err)) {
478         error_report_err(err);
479         return false;
480     }
481 
482     if (!d3d_texture2d_share(tex, &share_handle, &err)) {
483         error_report_err(err);
484         return false;
485     }
486 
487     success = DuplicateHandle(
488         GetCurrentProcess(),
489         share_handle,
490         ddl->peer_process,
491         &target_handle,
492         0,
493         FALSE, DUPLICATE_SAME_ACCESS);
494     if (!success) {
495         g_autofree char *msg = g_win32_error_message(GetLastError());
496         g_debug("Failed to DuplicateHandle: %s", msg);
497         CloseHandle(share_handle);
498         return false;
499     }
500 
501     ddl_discard_display_messages(ddl);
502 
503     qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
504         ddl->d3d11_proxy,
505         GPOINTER_TO_INT(target_handle),
506         backing_width,
507         backing_height,
508         backing_y_0_top,
509         x, y, w, h,
510         G_DBUS_CALL_FLAGS_NONE,
511         -1,
512         NULL, NULL, NULL);
513 
514     CloseHandle(share_handle);
515 
516     if (!d3d_texture2d_acquire0(tex, &err)) {
517         error_report_err(err);
518         return false;
519     }
520 
521     ddl->d3d_texture = tex;
522     ddl->ds_share = SHARE_KIND_D3DTEX;
523 
524     return true;
525 }
526 #endif /* CONFIG_OPENGL */
527 #else /* !WIN32 */
dbus_scanout_map(DBusDisplayListener * ddl)528 static bool dbus_scanout_map(DBusDisplayListener *ddl)
529 {
530     g_autoptr(GError) err = NULL;
531     g_autoptr(GUnixFDList) fd_list = NULL;
532 
533     if (ddl->ds_share == SHARE_KIND_MAPPED) {
534         return true;
535     }
536 
537     if (!ddl->can_share_map || ddl->ds->share_handle == SHAREABLE_NONE) {
538         return false;
539     }
540 
541     ddl_discard_display_messages(ddl);
542     fd_list = g_unix_fd_list_new();
543     if (g_unix_fd_list_append(fd_list, ddl->ds->share_handle, &err) != 0) {
544         g_debug("Failed to setup scanout map fdlist: %s", err->message);
545         ddl->can_share_map = false;
546         return false;
547     }
548 
549     if (!qemu_dbus_display1_listener_unix_map_call_scanout_map_sync(
550             ddl->map_proxy,
551             g_variant_new_handle(0),
552             ddl->ds->share_handle_offset,
553             surface_width(ddl->ds),
554             surface_height(ddl->ds),
555             surface_stride(ddl->ds),
556             surface_format(ddl->ds),
557             G_DBUS_CALL_FLAGS_NONE,
558             DBUS_DEFAULT_TIMEOUT,
559             fd_list,
560             NULL,
561             NULL,
562             &err)) {
563         g_debug("Failed to call ScanoutMap: %s", err->message);
564         ddl->can_share_map = false;
565         return false;
566     }
567 
568     ddl->ds_share = SHARE_KIND_MAPPED;
569 
570     return true;
571 }
572 #endif /* WIN32 */
573 
574 #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)575 static void dbus_scanout_texture(DisplayChangeListener *dcl,
576                                  uint32_t tex_id,
577                                  bool backing_y_0_top,
578                                  uint32_t backing_width,
579                                  uint32_t backing_height,
580                                  uint32_t x, uint32_t y,
581                                  uint32_t w, uint32_t h,
582                                  void *d3d_tex2d)
583 {
584     trace_dbus_scanout_texture(tex_id, backing_y_0_top,
585                                backing_width, backing_height, x, y, w, h);
586 #ifdef CONFIG_GBM
587     g_autoptr(QemuDmaBuf) dmabuf = NULL;
588     int fd[DMABUF_MAX_PLANES], num_planes;
589     uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc;
590     uint64_t modifier;
591 
592     assert(tex_id);
593     if (!egl_dmabuf_export_texture(tex_id, fd, (EGLint *)offset, (EGLint *)stride,
594                                    (EGLint *)&fourcc, &num_planes, &modifier)) {
595         error_report("%s: failed to export dmabuf for texture", __func__);
596         return;
597     }
598     dmabuf = qemu_dmabuf_new(w, h, offset, stride, x, y, backing_width,
599                              backing_height, fourcc, modifier, fd, num_planes,
600                              false, backing_y_0_top);
601 
602     dbus_scanout_dmabuf(dcl, dmabuf);
603     qemu_dmabuf_close(dmabuf);
604 #endif
605 
606 #ifdef WIN32
607     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
608 
609     /* there must be a matching gfx_switch before */
610     assert(surface_width(ddl->ds) == w);
611     assert(surface_height(ddl->ds) == h);
612 
613     if (d3d_tex2d) {
614         dbus_scanout_share_d3d_texture(ddl, d3d_tex2d, backing_y_0_top,
615                                        backing_width, backing_height, x, y, w, h);
616     } else {
617         dbus_scanout_map(ddl);
618         egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
619     }
620 #endif
621 }
622 
623 #ifdef CONFIG_GBM
dbus_cursor_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf,bool have_hot,uint32_t hot_x,uint32_t hot_y)624 static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
625                                QemuDmaBuf *dmabuf, bool have_hot,
626                                uint32_t hot_x, uint32_t hot_y)
627 {
628     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
629     DisplaySurface *ds;
630     GVariant *v_data = NULL;
631     egl_fb cursor_fb = EGL_FB_INIT;
632     uint32_t width, height, texture;
633 
634     if (!dmabuf) {
635         qemu_dbus_display1_listener_call_mouse_set(
636             ddl->proxy, 0, 0, false,
637             G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
638         return;
639     }
640 
641     ddl_discard_cursor_messages(ddl);
642 
643     egl_dmabuf_import_texture(dmabuf);
644     texture = qemu_dmabuf_get_texture(dmabuf);
645     if (!texture) {
646         return;
647     }
648 
649     width = qemu_dmabuf_get_width(dmabuf);
650     height = qemu_dmabuf_get_height(dmabuf);
651 
652     egl_fb_setup_for_tex(&cursor_fb, width, height, texture, false);
653     ds = qemu_create_displaysurface(width, height);
654     egl_fb_read(ds, &cursor_fb);
655 
656     v_data = g_variant_new_from_data(
657         G_VARIANT_TYPE("ay"),
658         surface_data(ds),
659         surface_width(ds) * surface_height(ds) * 4,
660         TRUE,
661         (GDestroyNotify)qemu_free_displaysurface,
662         ds);
663     qemu_dbus_display1_listener_call_cursor_define(
664         ddl->proxy,
665         surface_width(ds),
666         surface_height(ds),
667         hot_x,
668         hot_y,
669         v_data,
670         G_DBUS_CALL_FLAGS_NONE,
671         -1,
672         NULL,
673         NULL,
674         NULL);
675 }
676 
dbus_release_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)677 static void dbus_release_dmabuf(DisplayChangeListener *dcl,
678                                 QemuDmaBuf *dmabuf)
679 {
680     dbus_scanout_disable(dcl);
681 }
682 #endif /* GBM */
683 
dbus_gl_cursor_position(DisplayChangeListener * dcl,uint32_t pos_x,uint32_t pos_y)684 static void dbus_gl_cursor_position(DisplayChangeListener *dcl,
685                                  uint32_t pos_x, uint32_t pos_y)
686 {
687     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
688 
689     qemu_dbus_display1_listener_call_mouse_set(
690         ddl->proxy, pos_x, pos_y, true,
691         G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
692 }
693 
dbus_scanout_update(DisplayChangeListener * dcl,uint32_t x,uint32_t y,uint32_t w,uint32_t h)694 static void dbus_scanout_update(DisplayChangeListener *dcl,
695                                 uint32_t x, uint32_t y,
696                                 uint32_t w, uint32_t h)
697 {
698     dbus_call_update_gl(dcl, x, y, w, h);
699 }
700 
dbus_gl_refresh(DisplayChangeListener * dcl)701 static void dbus_gl_refresh(DisplayChangeListener *dcl)
702 {
703     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
704 
705     graphic_hw_update(dcl->con);
706 
707     if (!ddl->ds || qemu_console_is_gl_blocked(ddl->dcl.con)) {
708         return;
709     }
710 
711 #ifdef CONFIG_PIXMAN
712     int n_rects = pixman_region32_n_rects(&ddl->gl_damage);
713 
714     for (int i = 0; i < n_rects; i++) {
715         pixman_box32_t *box;
716         box = pixman_region32_rectangles(&ddl->gl_damage, NULL) + i;
717         /* TODO: Add a UpdateList call to send multiple updates at once */
718         dbus_call_update_gl(dcl, box->x1, box->y1,
719                             box->x2 - box->x1, box->y2 - box->y1);
720     }
721     pixman_region32_clear(&ddl->gl_damage);
722 #else
723     if (ddl->gl_damage) {
724         dbus_call_update_gl(dcl, 0, 0,
725                             surface_width(ddl->ds), surface_height(ddl->ds));
726         ddl->gl_damage = 0;
727     }
728 #endif
729 }
730 #endif /* OPENGL */
731 
dbus_refresh(DisplayChangeListener * dcl)732 static void dbus_refresh(DisplayChangeListener *dcl)
733 {
734     graphic_hw_update(dcl->con);
735 }
736 
737 #ifdef CONFIG_OPENGL
dbus_gl_gfx_update(DisplayChangeListener * dcl,int x,int y,int w,int h)738 static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
739                                int x, int y, int w, int h)
740 {
741     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
742 
743 #ifdef CONFIG_PIXMAN
744     pixman_region32_t rect_region;
745     pixman_region32_init_rect(&rect_region, x, y, w, h);
746     pixman_region32_union(&ddl->gl_damage, &ddl->gl_damage, &rect_region);
747     pixman_region32_fini(&rect_region);
748 #else
749     ddl->gl_damage++;
750 #endif
751 }
752 #endif
753 
dbus_gfx_update_sub(DBusDisplayListener * ddl,int x,int y,int w,int h)754 static void dbus_gfx_update_sub(DBusDisplayListener *ddl,
755                                 int x, int y, int w, int h)
756 {
757     pixman_image_t *img;
758     size_t stride;
759     GVariant *v_data;
760 
761     /* make a copy, since gvariant only handles linear data */
762     stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
763     img = pixman_image_create_bits(surface_format(ddl->ds),
764                                    w, h, NULL, stride);
765 #ifdef CONFIG_PIXMAN
766     pixman_image_composite(PIXMAN_OP_SRC, ddl->ds->image, NULL, img,
767                            x, y, 0, 0, 0, 0, w, h);
768 #else
769     {
770         uint8_t *src = (uint8_t *)pixman_image_get_data(ddl->ds->image);
771         uint8_t *dst = (uint8_t *)pixman_image_get_data(img);
772         int bp = PIXMAN_FORMAT_BPP(surface_format(ddl->ds)) / 8;
773         int hh;
774 
775         for (hh = 0; hh < h; hh++) {
776             memcpy(&dst[stride * hh],
777                    &src[surface_stride(ddl->ds) * (hh + y) + x * bp],
778                    stride);
779         }
780     }
781 #endif
782     v_data = g_variant_new_from_data(
783         G_VARIANT_TYPE("ay"),
784         pixman_image_get_data(img),
785         pixman_image_get_stride(img) * h,
786         TRUE,
787         (GDestroyNotify)pixman_image_unref,
788         img);
789     qemu_dbus_display1_listener_call_update(ddl->proxy,
790         x, y, w, h, pixman_image_get_stride(img), pixman_image_get_format(img),
791         v_data,
792         G_DBUS_CALL_FLAGS_NONE,
793         DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
794 }
795 
ddl_scanout(DBusDisplayListener * ddl)796 static void ddl_scanout(DBusDisplayListener *ddl)
797 {
798     GVariant *v_data;
799 
800     v_data = g_variant_new_from_data(
801         G_VARIANT_TYPE("ay"), surface_data(ddl->ds),
802         surface_stride(ddl->ds) * surface_height(ddl->ds), TRUE,
803         (GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image));
804 
805     ddl_discard_display_messages(ddl);
806 
807     qemu_dbus_display1_listener_call_scanout(
808         ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds),
809         surface_stride(ddl->ds), surface_format(ddl->ds), v_data,
810         G_DBUS_CALL_FLAGS_NONE, DBUS_DEFAULT_TIMEOUT, NULL, NULL,
811         g_object_ref(ddl));
812 }
813 
dbus_gfx_update(DisplayChangeListener * dcl,int x,int y,int w,int h)814 static void dbus_gfx_update(DisplayChangeListener *dcl,
815                             int x, int y, int w, int h)
816 {
817     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
818 
819     assert(ddl->ds);
820 
821     trace_dbus_update(x, y, w, h);
822 
823     if (dbus_scanout_map(ddl)) {
824 #ifdef WIN32
825         qemu_dbus_display1_listener_win32_map_call_update_map(
826             ddl->map_proxy,
827             x, y, w, h,
828             G_DBUS_CALL_FLAGS_NONE,
829             DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
830 #else
831         qemu_dbus_display1_listener_unix_map_call_update_map(
832             ddl->map_proxy,
833             x, y, w, h,
834             G_DBUS_CALL_FLAGS_NONE,
835             DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
836 #endif
837         return;
838     }
839 
840     if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
841         return ddl_scanout(ddl);
842     }
843 
844     dbus_gfx_update_sub(ddl, x, y, w, h);
845 }
846 
847 #ifdef CONFIG_OPENGL
dbus_gl_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface)848 static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
849                                struct DisplaySurface *new_surface)
850 {
851     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
852 
853     trace_dbus_gl_gfx_switch(new_surface);
854 
855     ddl->ds = new_surface;
856     ddl->ds_share = SHARE_KIND_NONE;
857     if (ddl->ds) {
858         int width = surface_width(ddl->ds);
859         int height = surface_height(ddl->ds);
860 
861         /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
862         dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false,
863                              width, height, 0, 0, width, height, NULL);
864     }
865 }
866 #endif
867 
dbus_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface)868 static void dbus_gfx_switch(DisplayChangeListener *dcl,
869                             struct DisplaySurface *new_surface)
870 {
871     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
872 
873     ddl->ds = new_surface;
874     ddl->ds_share = SHARE_KIND_NONE;
875 }
876 
dbus_mouse_set(DisplayChangeListener * dcl,int x,int y,bool on)877 static void dbus_mouse_set(DisplayChangeListener *dcl,
878                            int x, int y, bool on)
879 {
880     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
881 
882     qemu_dbus_display1_listener_call_mouse_set(
883         ddl->proxy, x, y, on, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
884 }
885 
dbus_cursor_define(DisplayChangeListener * dcl,QEMUCursor * c)886 static void dbus_cursor_define(DisplayChangeListener *dcl,
887                                QEMUCursor *c)
888 {
889     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
890     GVariant *v_data = NULL;
891 
892     ddl_discard_cursor_messages(ddl);
893 
894     v_data = g_variant_new_from_data(
895         G_VARIANT_TYPE("ay"),
896         c->data,
897         c->width * c->height * 4,
898         TRUE,
899         (GDestroyNotify)cursor_unref,
900         cursor_ref(c));
901 
902     qemu_dbus_display1_listener_call_cursor_define(
903         ddl->proxy,
904         c->width,
905         c->height,
906         c->hot_x,
907         c->hot_y,
908         v_data,
909         G_DBUS_CALL_FLAGS_NONE,
910         -1,
911         NULL,
912         NULL,
913         NULL);
914 }
915 
916 #ifdef CONFIG_OPENGL
917 const DisplayChangeListenerOps dbus_gl_dcl_ops = {
918     .dpy_name                = "dbus-gl",
919     .dpy_gfx_update          = dbus_gl_gfx_update,
920     .dpy_gfx_switch          = dbus_gl_gfx_switch,
921     .dpy_gfx_check_format    = console_gl_check_format,
922     .dpy_refresh             = dbus_gl_refresh,
923     .dpy_mouse_set           = dbus_mouse_set,
924     .dpy_cursor_define       = dbus_cursor_define,
925 
926     .dpy_gl_scanout_disable  = dbus_scanout_disable,
927     .dpy_gl_scanout_texture  = dbus_scanout_texture,
928 #ifdef CONFIG_GBM
929     .dpy_gl_scanout_dmabuf   = dbus_scanout_dmabuf,
930     .dpy_gl_cursor_dmabuf    = dbus_cursor_dmabuf,
931     .dpy_gl_release_dmabuf   = dbus_release_dmabuf,
932 #endif
933     .dpy_gl_cursor_position  = dbus_gl_cursor_position,
934     .dpy_gl_update           = dbus_scanout_update,
935 };
936 #endif
937 
938 const DisplayChangeListenerOps dbus_dcl_ops = {
939     .dpy_name                = "dbus",
940     .dpy_gfx_update          = dbus_gfx_update,
941     .dpy_gfx_switch          = dbus_gfx_switch,
942     .dpy_refresh             = dbus_refresh,
943     .dpy_mouse_set           = dbus_mouse_set,
944     .dpy_cursor_define       = dbus_cursor_define,
945 };
946 
947 static void
dbus_display_listener_dispose(GObject * object)948 dbus_display_listener_dispose(GObject *object)
949 {
950     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
951 
952     unregister_displaychangelistener(&ddl->dcl);
953     g_clear_object(&ddl->conn);
954     g_clear_pointer(&ddl->bus_name, g_free);
955     g_clear_object(&ddl->proxy);
956 #ifdef WIN32
957     g_clear_object(&ddl->map_proxy);
958     g_clear_object(&ddl->d3d11_proxy);
959     g_clear_pointer(&ddl->peer_process, CloseHandle);
960 #ifdef CONFIG_PIXMAN
961     pixman_region32_fini(&ddl->gl_damage);
962 #endif
963 #ifdef CONFIG_OPENGL
964     egl_fb_destroy(&ddl->fb);
965 #endif
966 #else /* !WIN32 */
967     g_clear_object(&ddl->scanout_dmabuf_v2_proxy);
968 #endif
969 
970     G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
971 }
972 
973 static void
dbus_display_listener_constructed(GObject * object)974 dbus_display_listener_constructed(GObject *object)
975 {
976     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
977 
978     ddl->dcl.ops = &dbus_dcl_ops;
979 #ifdef CONFIG_OPENGL
980     if (display_opengl) {
981         ddl->dcl.ops = &dbus_gl_dcl_ops;
982     }
983 #endif
984 
985     G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object);
986 }
987 
988 static void
dbus_display_listener_class_init(DBusDisplayListenerClass * klass)989 dbus_display_listener_class_init(DBusDisplayListenerClass *klass)
990 {
991     GObjectClass *object_class = G_OBJECT_CLASS(klass);
992 
993     object_class->dispose = dbus_display_listener_dispose;
994     object_class->constructed = dbus_display_listener_constructed;
995 }
996 
997 static void
dbus_display_listener_init(DBusDisplayListener * ddl)998 dbus_display_listener_init(DBusDisplayListener *ddl)
999 {
1000 #ifdef CONFIG_PIXMAN
1001     pixman_region32_init(&ddl->gl_damage);
1002 #endif
1003 }
1004 
1005 const char *
dbus_display_listener_get_bus_name(DBusDisplayListener * ddl)1006 dbus_display_listener_get_bus_name(DBusDisplayListener *ddl)
1007 {
1008     return ddl->bus_name ?: "p2p";
1009 }
1010 
1011 DBusDisplayConsole *
dbus_display_listener_get_console(DBusDisplayListener * ddl)1012 dbus_display_listener_get_console(DBusDisplayListener *ddl)
1013 {
1014     return ddl->console;
1015 }
1016 
1017 static bool
dbus_display_listener_implements(DBusDisplayListener * ddl,const char * iface)1018 dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
1019 {
1020     QemuDBusDisplay1Listener *l = QEMU_DBUS_DISPLAY1_LISTENER(ddl->proxy);
1021     bool implements;
1022 
1023     implements = g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l), iface);
1024     if (!implements) {
1025         g_debug("Display listener does not implement: `%s`", iface);
1026     }
1027 
1028     return implements;
1029 }
1030 
1031 #ifdef WIN32
1032 static bool
dbus_display_listener_setup_peer_process(DBusDisplayListener * ddl)1033 dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
1034 {
1035     g_autoptr(GError) err = NULL;
1036     GDBusConnection *conn;
1037     GIOStream *stream;
1038     GSocket *sock;
1039     g_autoptr(GCredentials) creds = NULL;
1040     DWORD *pid;
1041 
1042     if (ddl->peer_process) {
1043         return true;
1044     }
1045 
1046     conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy));
1047     stream = g_dbus_connection_get_stream(conn);
1048 
1049     if (!G_IS_UNIX_CONNECTION(stream)) {
1050         return false;
1051     }
1052 
1053     sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream));
1054     creds = g_socket_get_credentials(sock, &err);
1055 
1056     if (!creds) {
1057         g_debug("Failed to get peer credentials: %s", err->message);
1058         return false;
1059     }
1060 
1061     pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID);
1062 
1063     if (pid == NULL) {
1064         g_debug("Failed to get peer PID");
1065         return false;
1066     }
1067 
1068     ddl->peer_process = OpenProcess(
1069         PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
1070         false, *pid);
1071 
1072     if (!ddl->peer_process) {
1073         g_autofree char *msg = g_win32_error_message(GetLastError());
1074         g_debug("Failed to OpenProcess: %s", msg);
1075         return false;
1076     }
1077 
1078     return true;
1079 }
1080 #endif
1081 
1082 static void
dbus_display_listener_setup_d3d11(DBusDisplayListener * ddl)1083 dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
1084 {
1085 #ifdef WIN32
1086     g_autoptr(GError) err = NULL;
1087 
1088     if (!dbus_display_listener_implements(ddl,
1089             "org.qemu.Display1.Listener.Win32.D3d11")) {
1090         return;
1091     }
1092 
1093     if (!dbus_display_listener_setup_peer_process(ddl)) {
1094         return;
1095     }
1096 
1097     ddl->d3d11_proxy =
1098         qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl->conn,
1099             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1100             NULL,
1101             "/org/qemu/Display1/Listener",
1102             NULL,
1103             &err);
1104     if (!ddl->d3d11_proxy) {
1105         g_debug("Failed to setup win32 d3d11 proxy: %s", err->message);
1106         return;
1107     }
1108 #endif
1109 }
1110 
1111 static void
dbus_display_listener_setup_shared_map(DBusDisplayListener * ddl)1112 dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
1113 {
1114     g_autoptr(GError) err = NULL;
1115 
1116 #ifdef WIN32
1117     if (!dbus_display_listener_implements(
1118             ddl, "org.qemu.Display1.Listener.Win32.Map")) {
1119         return;
1120     }
1121 
1122     if (!dbus_display_listener_setup_peer_process(ddl)) {
1123         return;
1124     }
1125 
1126     ddl->map_proxy =
1127         qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl->conn,
1128             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1129             NULL,
1130             "/org/qemu/Display1/Listener",
1131             NULL,
1132             &err);
1133     if (!ddl->map_proxy) {
1134         g_debug("Failed to setup win32 map proxy: %s", err->message);
1135         return;
1136     }
1137 
1138     ddl->can_share_map = true;
1139 #else /* !WIN32 */
1140     if (!dbus_display_listener_implements(
1141             ddl, "org.qemu.Display1.Listener.Unix.Map")) {
1142         return;
1143     }
1144     ddl->map_proxy = qemu_dbus_display1_listener_unix_map_proxy_new_sync(
1145         ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
1146         "/org/qemu/Display1/Listener", NULL, &err);
1147     if (!ddl->map_proxy) {
1148         g_debug("Failed to setup Unix map proxy: %s", err->message);
1149         return;
1150     }
1151 
1152     ddl->can_share_map = true;
1153 #endif
1154 }
1155 
dbus_display_listener_setup_scanout_dmabuf_v2(DBusDisplayListener * ddl)1156 static void dbus_display_listener_setup_scanout_dmabuf_v2(DBusDisplayListener *ddl)
1157 {
1158 #ifndef WIN32
1159     g_autoptr(GError) err = NULL;
1160 
1161     if (!dbus_display_listener_implements(
1162             ddl, "org.qemu.Display1.Listener.Unix.ScanoutDMABUF2")) {
1163         return;
1164     }
1165     ddl->scanout_dmabuf_v2_proxy =
1166         qemu_dbus_display1_listener_unix_scanout_dmabuf2_proxy_new_sync(
1167             ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
1168             "/org/qemu/Display1/Listener", NULL, &err);
1169     if (!ddl->scanout_dmabuf_v2_proxy) {
1170         g_debug("Failed to setup Unix scanout dmabuf v2 proxy: %s", err->message);
1171         return;
1172     }
1173 #endif
1174 }
1175 
1176 static GDBusMessage *
dbus_filter(GDBusConnection * connection,GDBusMessage * message,gboolean incoming,gpointer user_data)1177 dbus_filter(GDBusConnection *connection,
1178             GDBusMessage    *message,
1179             gboolean         incoming,
1180             gpointer         user_data)
1181 {
1182     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data);
1183     guint32 serial, discard_serial;
1184 
1185     if (incoming) {
1186         return message;
1187     }
1188 
1189     serial = g_dbus_message_get_serial(message);
1190 
1191     discard_serial = g_atomic_int_get(&ddl->display_serial_to_discard);
1192     if (serial <= discard_serial) {
1193         const char *member = g_dbus_message_get_member(message);
1194         static const char *const display_messages[] = {
1195             "Scanout",
1196             "Update",
1197 #ifdef CONFIG_GBM
1198             "ScanoutDMABUF",
1199             "UpdateDMABUF",
1200 #endif
1201             "ScanoutMap",
1202             "UpdateMap",
1203             "Disable",
1204             NULL,
1205         };
1206 
1207         if (g_strv_contains(display_messages, member)) {
1208             trace_dbus_filter(serial, discard_serial);
1209             g_object_unref(message);
1210             return NULL;
1211         }
1212     }
1213 
1214     discard_serial = g_atomic_int_get(&ddl->cursor_serial_to_discard);
1215     if (serial <= discard_serial) {
1216         const gchar *member = g_dbus_message_get_member(message);
1217         static const char *const cursor_messages[] = {
1218             "CursorDefine",
1219             NULL
1220         };
1221 
1222         if (g_strv_contains(cursor_messages, member)) {
1223             trace_dbus_filter(serial, discard_serial);
1224             g_object_unref(message);
1225             return NULL;
1226         }
1227     }
1228 
1229     return message;
1230 }
1231 
1232 DBusDisplayListener *
dbus_display_listener_new(const char * bus_name,GDBusConnection * conn,DBusDisplayConsole * console)1233 dbus_display_listener_new(const char *bus_name,
1234                           GDBusConnection *conn,
1235                           DBusDisplayConsole *console)
1236 {
1237     DBusDisplayListener *ddl;
1238     QemuConsole *con;
1239     g_autoptr(GError) err = NULL;
1240 
1241     ddl = g_object_new(DBUS_DISPLAY_TYPE_LISTENER, NULL);
1242     ddl->proxy =
1243         qemu_dbus_display1_listener_proxy_new_sync(conn,
1244             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1245             NULL,
1246             "/org/qemu/Display1/Listener",
1247             NULL,
1248             &err);
1249     if (!ddl->proxy) {
1250         error_report("Failed to setup proxy: %s", err->message);
1251         g_object_unref(conn);
1252         g_object_unref(ddl);
1253         return NULL;
1254     }
1255 
1256     ddl->dbus_filter = g_dbus_connection_add_filter(conn, dbus_filter, g_object_ref(ddl), g_object_unref);
1257     ddl->bus_name = g_strdup(bus_name);
1258     ddl->conn = conn;
1259     ddl->console = console;
1260 
1261     dbus_display_listener_setup_shared_map(ddl);
1262     trace_dbus_can_share_map(ddl->can_share_map);
1263     dbus_display_listener_setup_d3d11(ddl);
1264     dbus_display_listener_setup_scanout_dmabuf_v2(ddl);
1265 
1266     con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
1267     assert(con);
1268     ddl->dcl.con = con;
1269     register_displaychangelistener(&ddl->dcl);
1270 
1271     return ddl;
1272 }
1273