[Mesa-dev] [RFC v2 4/5] vulkan: Add support for out-fences in vkAcquireNextImage

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Thu Sep 28 08:25:27 UTC 2017


Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at 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



More information about the mesa-dev mailing list