From e84aa5e1dbeb6e4860f100123a5e03b4c7e77116 Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Fri, 11 Oct 2024 15:10:17 -0500 Subject: [PATCH] wayland_vk: use FIFO if commit-timing and fifo protocols are available A very long time annoyance with wayland was compositors indefinitely blocking our vo thread if the surface gets occluded in some way. We've worked around this by using mailbox and our own custom vsync function. Thankfully it looks like people are finally solving this and with these two protocols it should be possible to guarantee forward progress on vulkan which means all the workarounds we do shouldn't be needed. So we can just request fifo in this case as a default since all we want is standard vsync blocking. --- video/out/meson.build | 7 ++++++- video/out/vulkan/context_wayland.c | 19 +++++++++++-------- video/out/wayland_common.c | 18 ++++++++++++++++++ video/out/wayland_common.h | 7 +++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/video/out/meson.build b/video/out/meson.build index de93508217e0b..852ff147933ae 100644 --- a/video/out/meson.build +++ b/video/out/meson.build @@ -11,7 +11,7 @@ protocols = [[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'] wl_protocols_source = [] wl_protocols_headers = [] -foreach v: ['1.32'] +foreach v: ['1.32', '1.38'] features += {'wayland-protocols-' + v.replace('.', '-'): wayland['deps'][2].version().version_compare('>=' + v)} endforeach @@ -21,6 +21,11 @@ if features['wayland-protocols-1-32'] [wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml']] # required by cursor-shape endif +if features['wayland-protocols-1-38'] + protocols += [[wl_protocol_dir, 'staging/commit-timing/commit-timing-v1.xml'], + [wl_protocol_dir, 'staging/fifo/fifo-v1.xml']] +endif + foreach p: protocols xml = join_paths(p) wl_protocols_source += custom_target(xml.underscorify() + '_c', diff --git a/video/out/vulkan/context_wayland.c b/video/out/vulkan/context_wayland.c index eae5d25e7d3c4..5b979ed07bcdf 100644 --- a/video/out/vulkan/context_wayland.c +++ b/video/out/vulkan/context_wayland.c @@ -25,6 +25,7 @@ struct priv { struct mpvk_ctx vk; + bool use_fifo; }; static bool wayland_vk_check_visible(struct ra_ctx *ctx) @@ -35,8 +36,9 @@ static bool wayland_vk_check_visible(struct ra_ctx *ctx) static void wayland_vk_swap_buffers(struct ra_ctx *ctx) { struct vo_wayland_state *wl = ctx->vo->wl; + struct priv *p = ctx->priv; - if (wl->opts->wl_internal_vsync) + if ((!p->use_fifo && wl->opts->wl_internal_vsync == 1) || wl->opts->wl_internal_vsync == 2) vo_wayland_wait_frame(wl); if (wl->use_present) @@ -63,6 +65,7 @@ static bool wayland_vk_init(struct ra_ctx *ctx) { struct priv *p = ctx->priv = talloc_zero(ctx, struct priv); struct mpvk_ctx *vk = &p->vk; + struct vo_wayland_state *wl = ctx->vo->wl; int msgl = ctx->opts.probing ? MSGL_V : MSGL_ERR; if (!mpvk_init(vk, ctx, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) @@ -90,13 +93,13 @@ static bool wayland_vk_init(struct ra_ctx *ctx) goto error; } - /* Because in Wayland clients render whenever they receive a callback from - * the compositor, and the fact that the compositor usually stops sending - * callbacks once the surface is no longer visible, using FIFO here would - * mean the entire player would block on acquiring swapchain images. Hence, - * use MAILBOX to guarantee that there'll always be a swapchain image and - * the player won't block waiting on those */ - if (!ra_vk_ctx_init(ctx, vk, params, VK_PRESENT_MODE_MAILBOX_KHR)) + /* If the Wayland compositor does not support commit-timing and fifo + * protocols in addition to wp-presentation v2, the compositor will stop + * sending callbacks if the surface is no longer visible. This means using + * FIFO would block the entire vo thread which is just not good. Use MAILBOX + * for those compositors to avoid indefinite blocking. */ + p->use_fifo = wl->has_commit_timing && wl->has_fifo && wl->present_v2; + if (!ra_vk_ctx_init(ctx, vk, params, p->use_fifo ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_MAILBOX_KHR)) goto error; ra_add_native_resource(ctx->ra, "wl", ctx->vo->wl->display); diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 0c93577ee31a3..40498475877b3 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -56,6 +56,11 @@ #include "cursor-shape-v1.h" #endif +#if HAVE_WAYLAND_PROTOCOLS_1_38 +#include "commit-timing-v1.h" +#include "fifo-v1.h" +#endif + #if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 22 #define HAVE_WAYLAND_1_22 #endif @@ -1578,6 +1583,18 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id wl->single_pixel_manager = wl_registry_bind(reg, id, &wp_single_pixel_buffer_manager_v1_interface, ver); } +#if HAVE_WAYLAND_PROTOCOLS_1_38 + if (!strcmp(interface, wp_commit_timing_manager_v1_interface.name) && found++) { + ver = 1; + wl->has_commit_timing = true; + } + + if (!strcmp(interface, wp_fifo_manager_v1_interface.name) && found++) { + ver = 1; + wl->has_fifo = true; + } +#endif + if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name) && found++) { ver = 1; wl->fractional_scale_manager = wl_registry_bind(reg, id, &wp_fractional_scale_manager_v1_interface, ver); @@ -1592,6 +1609,7 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id if (!strcmp(interface, wp_presentation_interface.name) && found++) { ver = MPMIN(ver, 2); + wl->present_v2 = ver == 2; wl->presentation = wl_registry_bind(reg, id, &wp_presentation_interface, ver); wp_presentation_add_listener(wl->presentation, &pres_listener, wl); } diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index 23cca5b8e9594..05ad037319b07 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -85,6 +85,9 @@ struct vo_wayland_state { int timeout_count; int wakeup_pipe[2]; + /* commit-timing */ + bool has_commit_timing; + /* content-type */ struct wp_content_type_manager_v1 *content_type_manager; struct wp_content_type_v1 *content_type; @@ -94,6 +97,9 @@ struct vo_wayland_state { /* TODO: unvoid these if required wayland protocols is bumped to 1.32+ */ void *cursor_shape_manager; + /* fifo */ + bool has_fifo; + /* fractional-scale */ struct wp_fractional_scale_manager_v1 *fractional_scale_manager; struct wp_fractional_scale_v1 *fractional_scale; @@ -116,6 +122,7 @@ struct vo_wayland_state { struct mp_present *present; int64_t refresh_interval; bool present_clock; + bool present_v2; bool use_present; /* single-pixel-buffer */