Signed-off-by: Louis-Francis Ratté-Boulianne <l...@collabora.com> --- src/vulkan/wsi/wsi_common.h | 3 + src/vulkan/wsi/wsi_common_x11.c | 152 +++++++++++++++++++++++++++++++--------- 2 files changed, 121 insertions(+), 34 deletions(-)
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index e81c7be11a..9375678e82 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -61,6 +61,9 @@ struct wsi_image_fns { const VkSemaphore *semaphores, uint32_t semaphore_count, int *fd); + VkResult (*import_semaphore_fd)(VkDevice device, + VkSemaphore semaphore, + int fd); }; struct wsi_swapchain { diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index 1179eed9c7..1f6ba6da55 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -655,6 +655,7 @@ struct x11_image { bool busy; struct xshmfence * shm_fence; uint32_t wait_fence; + uint32_t idle_fence; uint32_t sync_fence; }; @@ -745,6 +746,7 @@ x11_handle_dri3_present_event(struct x11_swapchain *chain, for (unsigned i = 0; i < chain->base.image_count; i++) { if (chain->images[i].pixmap == idle->pixmap) { + chain->images[i].idle_fence = idle->idle_fence; chain->images[i].busy = false; if (chain->images[i].wait_fence) { xcb_void_cookie_t cookie; @@ -804,21 +806,79 @@ static uint64_t wsi_get_absolute_timeout(uint64_t timeout) return current_time + timeout; } +static int +x11_wait_for_fence(struct x11_swapchain *chain, + struct x11_image *image, + VkSemaphore semaphore) +{ + VkResult ret = VK_SUCCESS; + +#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 2 + if (image->idle_fence) { + xcb_void_cookie_t tmp_cookie; + + if (semaphore) { + struct wsi_swapchain *anv_chain = (struct wsi_swapchain *)chain; + xcb_dri3_dma_fence_fd_from_fence_cookie_t cookie; + xcb_dri3_dma_fence_fd_from_fence_reply_t *reply; + xcb_generic_error_t *error = NULL; + int *fds; + + cookie = xcb_dri3_dma_fence_fd_from_fence(chain->conn, + image->pixmap, + image->idle_fence); + reply = xcb_dri3_dma_fence_fd_from_fence_reply(chain->conn, + cookie, + &error); + if (error) + return VK_ERROR_OUT_OF_HOST_MEMORY; + fds = xcb_dri3_dma_fence_fd_from_fence_reply_fds(chain->conn, + reply); + free(reply); + ret = chain->base.image_fns->import_semaphore_fd(anv_chain->device, + semaphore, fds[0]); + if (ret != VK_SUCCESS) + close(fds[0]); + } else { + xcb_sync_await_fence_checked(chain->conn, 1, &image->idle_fence); + } + tmp_cookie = xcb_sync_destroy_fence(chain->conn, image->idle_fence); + xcb_discard_reply(chain->conn, tmp_cookie.sequence); + image->idle_fence = 0; + } else if (!chain->has_dma_fence) +#endif + { + xshmfence_await(image->shm_fence); + } + + return ret; +} + static VkResult x11_acquire_next_image_poll_x11(struct x11_swapchain *chain, - uint32_t *image_index, uint64_t timeout) + uint32_t *image_index, + VkSemaphore semaphore, + uint64_t timeout) { xcb_generic_event_t *event; struct pollfd pfds; uint64_t atimeout; while (1) { - for (uint32_t i = 0; i < chain->base.image_count; i++) { - if (!chain->images[i].busy) { - /* We found a non-busy image */ - xshmfence_await(chain->images[i].shm_fence); - *image_index = i; - chain->images[i].busy = true; - return VK_SUCCESS; + // XXX first pass, try to find non-busy images, second pass, idle_fence is fine + // XXX if there is no semaphore, we need to wait for the fence + // XXX this way we can use all available images instead of waiting for the first + // XXX one to be free. (problem is we might wait for an older one if all queued) + uint32_t num_passes = chain->has_dma_fence ? 2 : 1; + + for (uint32_t p = 0; p < num_passes; p++) { + for (uint32_t i = 0; i < chain->base.image_count; i++) { + if (!chain->images[i].busy && + ((p == 0 && !chain->images[i].idle_fence) || p == 1)) { + x11_wait_for_fence(chain, &chain->images[i], semaphore); + *image_index = i; + chain->images[i].busy = true; + return VK_SUCCESS; + } } } @@ -866,7 +926,9 @@ x11_acquire_next_image_poll_x11(struct x11_swapchain *chain, static VkResult x11_acquire_next_image_from_queue(struct x11_swapchain *chain, - uint32_t *image_index_out, uint64_t timeout) + uint32_t *image_index_out, + VkSemaphore semaphore, + uint64_t timeout) { assert(chain->threaded); @@ -880,7 +942,7 @@ x11_acquire_next_image_from_queue(struct x11_swapchain *chain, } assert(image_index < chain->base.image_count); - xshmfence_await(chain->images[image_index].shm_fence); + x11_wait_for_fence(chain, &chain->images[image_index], semaphore); *image_index_out = image_index; @@ -899,11 +961,19 @@ x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index, int64_t divisor = 0; int64_t remainder = 0; + uint32_t idle_fence = image->sync_fence; if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) options |= XCB_PRESENT_OPTION_ASYNC; - xshmfence_reset(image->shm_fence); + if (chain->has_dma_fence) { +#if XCB_PRESENT_MAJOR_VERSION > 1 || XCB_PRESENT_MINOR_VERSION >= 2 + options |= XCB_PRESENT_OPTION_IDLE_FENCE; + idle_fence = xcb_generate_id(chain->conn); +#endif + } else { + xshmfence_reset(image->shm_fence); + } ++chain->send_sbc; xcb_void_cookie_t cookie = @@ -917,7 +987,7 @@ x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index, 0, /* y_off */ XCB_NONE, /* target_crtc */ image->wait_fence, - image->sync_fence, + idle_fence, options, target_msc, divisor, @@ -941,9 +1011,11 @@ x11_acquire_next_image(struct wsi_swapchain *anv_chain, VkResult result; if (chain->threaded) { - result = x11_acquire_next_image_from_queue(chain, image_index, timeout); + result = x11_acquire_next_image_from_queue(chain, image_index, + semaphore, timeout); } else { - result = x11_acquire_next_image_poll_x11(chain, image_index, timeout); + result = x11_acquire_next_image_poll_x11(chain, image_index, + semaphore, timeout); } if (result != VK_SUCCESS) { @@ -1159,28 +1231,32 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, image->wait_fence = 0; image->busy = false; - int fence_fd = xshmfence_alloc_shm(); - if (fence_fd < 0) - goto fail_pixmap; - - image->shm_fence = xshmfence_map_shm(fence_fd); - if (image->shm_fence == NULL) - goto fail_shmfence_alloc; + if (chain->has_dma_fence) { + image->shm_fence = 0; + image->sync_fence = 0; + } else { + int fence_fd = xshmfence_alloc_shm(); + if (fence_fd < 0) + goto fail_pixmap; + + image->shm_fence = xshmfence_map_shm(fence_fd); + if (image->shm_fence == NULL) { + close(fence_fd); + goto fail_pixmap; + } - image->sync_fence = xcb_generate_id(chain->conn); - xcb_dri3_fence_from_fd(chain->conn, - image->pixmap, - image->sync_fence, - false, - fence_fd); + image->sync_fence = xcb_generate_id(chain->conn); + xcb_dri3_fence_from_fd(chain->conn, + image->pixmap, + image->sync_fence, + false, + fence_fd); - xshmfence_trigger(image->shm_fence); + xshmfence_trigger(image->shm_fence); + } return VK_SUCCESS; -fail_shmfence_alloc: - close(fence_fd); - fail_pixmap: cookie = xcb_free_pixmap(chain->conn, image->pixmap); xcb_discard_reply(chain->conn, cookie.sequence); @@ -1197,9 +1273,11 @@ x11_image_finish(struct x11_swapchain *chain, { xcb_void_cookie_t cookie; - cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence); - xcb_discard_reply(chain->conn, cookie.sequence); - xshmfence_unmap_shm(image->shm_fence); + if (!chain->has_dma_fence) { + cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence); + xcb_discard_reply(chain->conn, cookie.sequence); + xshmfence_unmap_shm(image->shm_fence); + } if (image->wait_fence) { cookie = xcb_sync_destroy_fence(chain->conn, image->wait_fence); @@ -1207,6 +1285,12 @@ x11_image_finish(struct x11_swapchain *chain, image->wait_fence = 0; } + if (image->idle_fence) { + cookie = xcb_sync_destroy_fence(chain->conn, image->idle_fence); + xcb_discard_reply(chain->conn, cookie.sequence); + image->idle_fence = 0; + } + cookie = xcb_free_pixmap(chain->conn, image->pixmap); xcb_discard_reply(chain->conn, cookie.sequence); -- 2.13.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev