diff options
author | Lionel Landwerlin <[email protected]> | 2019-07-26 12:08:13 +0300 |
---|---|---|
committer | Lionel Landwerlin <[email protected]> | 2019-07-29 13:11:36 +0000 |
commit | 6659d11ff0c639c49823fdaa0cf23c7fef7f2582 (patch) | |
tree | 3e425f0a1570061ac17e1cf56d312b0cbd8b29d9 /src/vulkan/wsi | |
parent | d2d70c3bb579f8a8e0b7431eff164e85ca7bc4ab (diff) |
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 <[email protected]>
Reviewed-by: Eric Engestrom <[email protected]> (v2)
Reviewed-by: Daniel Stone <[email protected]>
Diffstat (limited to 'src/vulkan/wsi')
-rw-r--r-- | src/vulkan/wsi/wsi_common_wayland.c | 76 |
1 files 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 <errno.h> #include <string.h> #include <pthread.h> +#include <poll.h> #include "drm-uapi/drm_fourcc.h" @@ -40,6 +41,7 @@ #include "linux-dmabuf-unstable-v1-client-protocol.h" #include <util/hash_table.h> +#include <util/timespec.h> #include <util/u_vector.h> #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; } |