History

wayland: properly use tranche_formats when getting compositor formats

It's a bit roundabout, but we were doing this incorrectly before. The format table alone isn't good enough because it is possible the the compositor may advertise different formats for a specific device which is a subset of the format table. What we need to do is add formats based on the array in tranche_formats. Note that it is possible for the compositor to send multiple tranches (was not able to simulate this but it's allowed by the protocol). For mpv, we only care about the very first one which is supposed to be the most preferred one. The compositor can also send the entire chain of events (main device, format_table, tranches, etc.) all over again. We handle this in the wayland code, but handling this in mpv's core code isn't done. e.g. say a format in use was suddenly no longer supported. We ideally should do a full reconfig in this case, but that gets complicated and is pretty niche so save that for another day. Multiple GPUs isn't taken into account either. We just pick the first one. Not strictly correct, but close enough for us. Fixes #14544.

Dudemanguy committed 2 years ago

Commit 7a803301 parent 4d09cde3 files · +56 −12Browse files

Unified · Split

3 files
  1. video/out/wayland_common.c +45 −9
  2. video/out/wayland_common.h +9 −1
  3. video/out/wldmabuf/ra_wldmabuf.c +2 −2
video/out/wayland_common.c+45−9
@@ -1363,6 +1363,12 @@ static void format_table(void *data, · 1362 unmodified lines
1363{1363{
1364 struct vo_wayland_state *wl = data;1364 struct vo_wayland_state *wl = data;
1365 1365
1366 if (wl->compositor_format_size) {
1367 munmap(wl->compositor_format_map, wl->compositor_format_size);
1368 wl->compositor_format_map = NULL;
1369 wl->compositor_format_size = 0;
1370 }
1371
1366 void *map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);1372 void *map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
1367 close(fd);1373 close(fd);
1368 1374
@@ -1377,32 +1383,62 @@ static void main_device(void *data, · 8 unmodified lines
1377 struct wl_array *device)1383 struct wl_array *device)
1378{1384{
1379 struct vo_wayland_state *wl = data;1385 struct vo_wayland_state *wl = data;
1386 wl->add_tranche = true;
1380 1387
1381 // Despite being an array, the protocol specifically states there can only be
1382 // one main device so break as soon as we get one.
1383 dev_t *id;
1384 wl_array_for_each(id, device) {
1385 memcpy(&wl->main_device_id, id, sizeof(dev_t));
1386 break;
1387 }
1388 get_gpu_drm_formats(wl);
1389}1388}
1390 1389
1391static void tranche_done(void *data,1390static void tranche_done(void *data,
1392 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1)1391 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1)
1393{1392{
1393 struct vo_wayland_state *wl = data;
1394 wl->add_tranche = false;
1394}1395}
1395 1396
1396static void tranche_target_device(void *data,1397static void tranche_target_device(void *data,
1397 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,1398 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
1398 struct wl_array *device)1399 struct wl_array *device)
1399{1400{
1401 struct vo_wayland_state *wl = data;
1402 // Only use the first tranche device we get.
1403 if (wl->add_tranche) {
1404 dev_t *id;
1405 wl_array_for_each(id, device) {
1406 memcpy(&wl->target_device_id, id, sizeof(dev_t));
1407 break;
1408 }
1409 get_gpu_drm_formats(wl);
1410 }
1400}1411}
1401 1412
1402static void tranche_formats(void *data,1413static void tranche_formats(void *data,
1403 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,1414 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
1404 struct wl_array *indices)1415 struct wl_array *indices)
1405{1416{
1417 struct vo_wayland_state *wl = data;
1418
1419 // Only grab formats from the first tranche and ignore the rest.
1420 if (!wl->add_tranche)
1421 return;
1422
1423 // Should never happen.
1424 if (!wl->compositor_format_map) {
1425 MP_WARN(wl, "Compositor did not send a format and modifier table!\n");
1426 return;
1427 }
1428
1429 const compositor_format *formats = wl->compositor_format_map;
1430 MP_RESIZE_ARRAY(wl, wl->compositor_formats, indices->size);
1431 wl->num_compositor_formats = 0;
1432 uint16_t *index;
1433 wl_array_for_each(index, indices) {
1434 MP_TARRAY_APPEND(wl, wl->compositor_formats, wl->num_compositor_formats,
1435 (struct drm_format) {
1436 formats[*index].format,
1437 formats[*index].modifier,
1438 });
1439 MP_DBG(wl, "Compositor supports drm format: '%s(%016" PRIx64 ")'\n",
1440 mp_tag_str(formats[*index].format), formats[*index].modifier);
1441 }
1406}1442}
1407 1443
1408static void tranche_flags(void *data,1444static void tranche_flags(void *data,
@@ -1799,7 +1835,7 @@ static void get_gpu_drm_formats(struct vo_wayland_state *wl) · 390 unmodified lines
1799 drmModePlaneRes *res = NULL;1835 drmModePlaneRes *res = NULL;
1800 drmModePlane *plane = NULL;1836 drmModePlane *plane = NULL;
1801 1837
1802 if (drmGetDeviceFromDevId(wl->main_device_id, 0, &device) != 0) {1838 if (drmGetDeviceFromDevId(wl->target_device_id, 0, &device) != 0) {
1803 MP_WARN(wl, "Unable to get drm device from device id: %s\n", mp_strerror(errno));1839 MP_WARN(wl, "Unable to get drm device from device id: %s\n", mp_strerror(errno));
1804 goto done;1840 goto done;
1805 }1841 }
video/out/wayland_common.h+9−1
@@ -30,6 +30,11 @@ typedef struct { · 29 unmodified lines
30 uint64_t modifier;30 uint64_t modifier;
31} compositor_format;31} compositor_format;
32 32
33struct drm_format {
34 uint32_t format;
35 uint64_t modifier;
36};
37
33struct vo_wayland_state {38struct vo_wayland_state {
34 struct m_config_cache *opts_cache;39 struct m_config_cache *opts_cache;
35 struct mp_log *log;40 struct mp_log *log;
@@ -102,11 +107,14 @@ struct vo_wayland_state { · 66 unmodified lines
102 struct zwp_idle_inhibitor_v1 *idle_inhibitor;107 struct zwp_idle_inhibitor_v1 *idle_inhibitor;
103 108
104 /* linux-dmabuf */109 /* linux-dmabuf */
105 dev_t main_device_id;110 dev_t target_device_id;
106 struct zwp_linux_dmabuf_v1 *dmabuf;111 struct zwp_linux_dmabuf_v1 *dmabuf;
107 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback;112 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback;
113 bool add_tranche;
108 compositor_format *compositor_format_map;114 compositor_format *compositor_format_map;
109 uint32_t compositor_format_size;115 uint32_t compositor_format_size;
116 struct drm_format *compositor_formats;
117 int num_compositor_formats;
110 uint32_t *gpu_formats;118 uint32_t *gpu_formats;
111 int num_gpu_formats;119 int num_gpu_formats;
112 120
video/out/wldmabuf/ra_wldmabuf.c+2−2
@@ -32,7 +32,7 @@ bool ra_compatible_format(struct ra *ra, int imgfmt, uint32_t drm_format, uint64 · 31 unmodified lines
32{32{
33 struct priv *p = ra->priv;33 struct priv *p = ra->priv;
34 struct vo_wayland_state *wl = p->vo->wl;34 struct vo_wayland_state *wl = p->vo->wl;
35 const compositor_format *formats = wl->compositor_format_map;35 struct drm_format *formats = wl->compositor_formats;
36 36
37 37
38 // If we were able to make the DRM query, filter out the GPU formats.38 // If we were able to make the DRM query, filter out the GPU formats.
@@ -50,7 +50,7 @@ bool ra_compatible_format(struct ra *ra, int imgfmt, uint32_t drm_format, uint64 · 11 unmodified lines
50 }50 }
51 51
52 // Always check if the compositor supports the format.52 // Always check if the compositor supports the format.
53 for (int i = 0; i < wl->compositor_format_size / sizeof(compositor_format); i++) {53 for (int i = 0; i < wl->num_compositor_formats; ++i) {
54 if (drm_format == formats[i].format && modifier == formats[i].modifier)54 if (drm_format == formats[i].format && modifier == formats[i].modifier)
55 return true;55 return true;
56 }56 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t