From 6659d11ff0c639c49823fdaa0cf23c7fef7f2582 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Fri, 26 Jul 2019 12:08:13 +0300 Subject: [PATCH] vulkan/wsi/wayland: implement acquire timeout v2: Eric's nits v3: Reuse timespec utils (Daniel) Deal with ppoll being interrupted by a signal (Daniel) v4: Remove unnecessary time check v5: Deal with EAGAIN from wl_display_prepare_read_queue() (Daniel) Signed-off-by: Lionel Landwerlin Reviewed-by: Eric Engestrom (v2) Reviewed-by: Daniel Stone --- src/vulkan/wsi/wsi_common_wayland.c | 76 +++++++++++++++++++---------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c index bf473833e02..438c2f50da3 100644 --- a/src/vulkan/wsi/wsi_common_wayland.c +++ b/src/vulkan/wsi/wsi_common_wayland.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "drm-uapi/drm_fourcc.h" @@ -40,6 +41,7 @@ #include "linux-dmabuf-unstable-v1-client-protocol.h" #include +#include #include #define typed_memcpy(dest, src, count) ({ \ @@ -754,27 +756,23 @@ wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, uint32_t *image_index) { struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; + struct timespec start_time, end_time; + struct timespec rel_timeout; + int wl_fd = wl_display_get_fd(chain->display->wl_display); -#ifdef DEBUG - /* - * TODO: We need to implement this - */ - if (info->timeout != 0 && info->timeout != UINT64_MAX) - { - fprintf(stderr, "timeout not supported; ignoring"); - } -#endif + timespec_from_nsec(&rel_timeout, info->timeout); - int ret = wl_display_dispatch_queue_pending(chain->display->wl_display, - chain->display->queue); - /* XXX: I'm not sure if out-of-date is the right error here. If - * wl_display_dispatch_queue_pending fails it most likely means we got - * kicked by the server so this seems more-or-less correct. - */ - if (ret < 0) - return VK_ERROR_OUT_OF_DATE_KHR; + clock_gettime(CLOCK_MONOTONIC, &start_time); + timespec_add(&end_time, &rel_timeout, &start_time); while (1) { + /* Try to dispatch potential events. */ + int ret = wl_display_dispatch_queue_pending(chain->display->wl_display, + chain->display->queue); + if (ret < 0) + return VK_ERROR_OUT_OF_DATE_KHR; + + /* Try to find a free image. */ for (uint32_t i = 0; i < chain->base.image_count; i++) { if (!chain->images[i].busy) { /* We found a non-busy image */ @@ -784,16 +782,44 @@ wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, } } - /* We now have to do a blocking dispatch, because all our images - * are in use and we cannot return one until the server does. However, - * if the client has requested non-blocking ANI, then we tell it up front - * that we have nothing to return. - */ - if (info->timeout == 0) + /* Check for timeout. */ + struct timespec current_time; + clock_gettime(CLOCK_MONOTONIC, ¤t_time); + if (timespec_after(¤t_time, &end_time)) return VK_NOT_READY; - int ret = wl_display_roundtrip_queue(chain->display->wl_display, - chain->display->queue); + /* Try to read events from the server. */ + ret = wl_display_prepare_read_queue(chain->display->wl_display, + chain->display->queue); + if (ret < 0) { + /* Another thread might have read events for our queue already. Go + * back to dispatch them. + */ + if (errno == EAGAIN) + continue; + return VK_ERROR_OUT_OF_DATE_KHR; + } + + struct pollfd pollfd = { + .fd = wl_fd, + .events = POLLIN + }; + timespec_sub(&rel_timeout, &end_time, ¤t_time); + ret = ppoll(&pollfd, 1, &rel_timeout, NULL); + if (ret <= 0) { + int lerrno = errno; + wl_display_cancel_read(chain->display->wl_display); + if (ret < 0) { + /* If ppoll() was interrupted, try again. */ + if (lerrno == EINTR || lerrno == EAGAIN) + continue; + return VK_ERROR_OUT_OF_DATE_KHR; + } + assert(ret == 0); + continue; + } + + ret = wl_display_read_events(chain->display->wl_display); if (ret < 0) return VK_ERROR_OUT_OF_DATE_KHR; } -- 2.30.2