Mesa (master): venus: stop using vn_renderer_sync in vn_fence

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Apr 14 21:23:55 UTC 2021


Module: Mesa
Branch: master
Commit: 4ffb0265cc3b922b866ea2a10503f26a9d316939
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4ffb0265cc3b922b866ea2a10503f26a9d316939

Author: Chia-I Wu <olvaffe at gmail.com>
Date:   Thu Apr  1 15:22:17 2021 -0700

venus: stop using vn_renderer_sync in vn_fence

Move away from vn_renderer_sync and toward a userspace-only solution
temporarily until the kernel does what we need.

Signed-off-by: Chia-I Wu <olvaffe at gmail.com>
Reviewed-by: Yiwei Zhang <zzyiwei at chromium.org>
Reviewed-by: Ryan Neph <ryanneph at google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10146>

---

 src/virtio/vulkan/vn_device.c |  28 +++---
 src/virtio/vulkan/vn_queue.c  | 204 +++++++++++++++++-------------------------
 2 files changed, 94 insertions(+), 138 deletions(-)

diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c
index 268678d2c20..569f0fe79bd 100644
--- a/src/virtio/vulkan/vn_device.c
+++ b/src/virtio/vulkan/vn_device.c
@@ -1362,24 +1362,22 @@ static void
 vn_physical_device_init_external_fence_handles(
    struct vn_physical_device *physical_dev)
 {
-   if (!physical_dev->instance->renderer_info.has_external_sync)
-      return;
-
-   /* In the current model, a vn_fence can be implemented entirely on top of
-    * vn_renderer_sync.  All operations can go through the renderer sync.
+   /* The current code manipulates the host-side VkFence directly.
+    * vkWaitForFences is translated to repeated vkGetFenceStatus.
     *
-    * The current code still creates a host-side VkFence, which can be
-    * eliminated.  The renderer also lacks proper external sync (i.e.,
-    * drm_syncobj) support and we can only support handle types with copy
-    * transference (i.e., sync fds).
+    * External fence is not possible currently.  At best, we could cheat by
+    * translating vkGetFenceFdKHR to vkWaitForFences and returning -1, when
+    * the handle type is sync file.
     *
-    * We are considering creating a vn_renderer_sync from a host-side VkFence
-    * instead, similar to how a vn_renderer_bo is created from a host-side
-    * VkDeviceMemory.  That will require tons of works on the host side, but
-    * should allow us to get rid of ring<->renderer syncs in vkQueueSubmit.
+    * We would like to create a vn_renderer_sync from a host-side VkFence,
+    * similar to how a vn_renderer_bo is created from a host-side
+    * VkDeviceMemory.  That would require kernel support and tons of works on
+    * the host side.  If we had that, and we kept both the vn_renderer_sync
+    * and the host-side VkFence in sync, we would have the freedom to use
+    * either of them depending on the occasions, and support external fences
+    * and idle waiting.
     */
-   physical_dev->external_fence_handles =
-      VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+   physical_dev->external_fence_handles = 0;
 }
 
 static void
diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c
index 239343189af..2818e3b2667 100644
--- a/src/virtio/vulkan/vn_queue.c
+++ b/src/virtio/vulkan/vn_queue.c
@@ -174,8 +174,6 @@ vn_queue_submission_count_semaphores(struct vn_queue_submission *submit)
 
    submit->sync_count =
       submit->signal_semaphore_count - submit->signal_device_only_count;
-   if (submit->fence != VK_NULL_HANDLE)
-      submit->sync_count++;
 }
 
 static VkResult
@@ -358,23 +356,6 @@ vn_queue_submission_setup_batch_syncs(struct vn_queue_submission *submit,
    return sync_count;
 }
 
-static uint32_t
-vn_queue_submission_setup_fence_sync(struct vn_queue_submission *submit,
-                                     uint32_t sync_base)
-{
-   if (submit->fence == VK_NULL_HANDLE)
-      return 0;
-
-   struct vn_fence *fence = vn_fence_from_handle(submit->fence);
-   struct vn_sync_payload *payload = fence->payload;
-
-   assert(payload->type == VN_SYNC_TYPE_SYNC);
-   submit->temp.syncs[sync_base] = payload->sync;
-   submit->temp.sync_values[sync_base] = 1;
-
-   return 1;
-}
-
 static void
 vn_queue_submission_setup_batches(struct vn_queue_submission *submit)
 {
@@ -416,8 +397,6 @@ vn_queue_submission_setup_batches(struct vn_queue_submission *submit)
       }
    }
 
-   sync_base += vn_queue_submission_setup_fence_sync(submit, sync_base);
-
    assert(sync_base == submit->sync_count);
 }
 
@@ -711,8 +690,8 @@ vn_fence_init_payloads(struct vn_device *dev,
                        const VkAllocationCallbacks *alloc)
 {
    struct vn_renderer_sync *perm_sync;
-   VkResult result = vn_renderer_sync_create_fence(dev->instance->renderer,
-                                                   signaled, 0, &perm_sync);
+   VkResult result =
+      vn_renderer_sync_create_empty(dev->instance->renderer, &perm_sync);
    if (result != VK_SUCCESS)
       return result;
 
@@ -724,7 +703,8 @@ vn_fence_init_payloads(struct vn_device *dev,
       return result;
    }
 
-   fence->permanent.type = VN_SYNC_TYPE_SYNC;
+   /* perm_sync is unused */
+   fence->permanent.type = VN_SYNC_TYPE_DEVICE_ONLY;
    fence->permanent.sync = perm_sync;
 
    /* temp_sync is uninitialized */
@@ -827,8 +807,7 @@ vn_ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences)
 
       vn_sync_payload_release(dev, &fence->temporary);
 
-      assert(perm->type == VN_SYNC_TYPE_SYNC);
-      vn_renderer_sync_reset(perm->sync, 0);
+      assert(perm->type == VN_SYNC_TYPE_DEVICE_ONLY);
       fence->payload = perm;
    }
 
@@ -843,12 +822,9 @@ vn_GetFenceStatus(VkDevice device, VkFence _fence)
    struct vn_sync_payload *payload = fence->payload;
 
    VkResult result;
-   uint64_t val;
    switch (payload->type) {
-   case VN_SYNC_TYPE_SYNC:
-      result = vn_renderer_sync_read(payload->sync, &val);
-      if (result == VK_SUCCESS && !val)
-         result = VK_NOT_READY;
+   case VN_SYNC_TYPE_DEVICE_ONLY:
+      result = vn_call_vkGetFenceStatus(dev->instance, device, _fence);
       break;
    case VN_SYNC_TYPE_WSI_SIGNALED:
       result = VK_SUCCESS;
@@ -861,6 +837,55 @@ vn_GetFenceStatus(VkDevice device, VkFence _fence)
    return vn_result(dev->instance, result);
 }
 
+static VkResult
+vn_find_first_signaled_fence(VkDevice device,
+                             const VkFence *fences,
+                             uint32_t count)
+{
+   for (uint32_t i = 0; i < count; i++) {
+      VkResult result = vn_GetFenceStatus(device, fences[i]);
+      if (result == VK_SUCCESS || result < 0)
+         return result;
+   }
+   return VK_NOT_READY;
+}
+
+static VkResult
+vn_remove_signaled_fences(VkDevice device, VkFence *fences, uint32_t *count)
+{
+   uint32_t cur = 0;
+   for (uint32_t i = 0; i < *count; i++) {
+      VkResult result = vn_GetFenceStatus(device, fences[i]);
+      if (result != VK_SUCCESS) {
+         if (result < 0)
+            return result;
+         fences[cur++] = fences[i];
+      }
+   }
+
+   *count = cur;
+   return cur ? VK_NOT_READY : VK_SUCCESS;
+}
+
+static VkResult
+vn_update_sync_result(VkResult result, int64_t abs_timeout, uint32_t *iter)
+{
+   switch (result) {
+   case VK_NOT_READY:
+      if (abs_timeout != OS_TIMEOUT_INFINITE &&
+          os_time_get_nano() >= abs_timeout)
+         result = VK_TIMEOUT;
+      else
+         vn_relax(iter);
+      break;
+   default:
+      assert(result == VK_SUCCESS || result < 0);
+      break;
+   }
+
+   return result;
+}
+
 VkResult
 vn_WaitForFences(VkDevice device,
                  uint32_t fenceCount,
@@ -871,59 +896,33 @@ vn_WaitForFences(VkDevice device,
    struct vn_device *dev = vn_device_from_handle(device);
    const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
 
-   struct vn_renderer_sync *local_syncs[8];
-   uint64_t local_sync_vals[8];
-   struct vn_renderer_sync **syncs = local_syncs;
-   uint64_t *sync_vals = local_sync_vals;
-   if (fenceCount > ARRAY_SIZE(local_syncs)) {
-      syncs = vk_alloc(alloc, sizeof(*syncs) * fenceCount, VN_DEFAULT_ALIGN,
-                       VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
-      sync_vals =
-         vk_alloc(alloc, sizeof(*sync_vals) * fenceCount, VN_DEFAULT_ALIGN,
-                  VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
-      if (!syncs || !sync_vals) {
-         vk_free(alloc, syncs);
-         vk_free(alloc, sync_vals);
-         return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
+   const int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
+   VkResult result = VK_NOT_READY;
+   uint32_t iter = 0;
+   if (fenceCount > 1 && waitAll) {
+      VkFence local_fences[8];
+      VkFence *fences = local_fences;
+      if (fenceCount > ARRAY_SIZE(local_fences)) {
+         fences =
+            vk_alloc(alloc, sizeof(*fences) * fenceCount, VN_DEFAULT_ALIGN,
+                     VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+         if (!fences)
+            return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
       }
-   }
+      memcpy(fences, pFences, sizeof(*fences) * fenceCount);
 
-   uint32_t wait_count = 0;
-   uint32_t signaled_count = 0;
-   for (uint32_t i = 0; i < fenceCount; i++) {
-      struct vn_fence *fence = vn_fence_from_handle(pFences[i]);
-      const struct vn_sync_payload *payload = fence->payload;
-
-      switch (payload->type) {
-      case VN_SYNC_TYPE_SYNC:
-         syncs[wait_count] = payload->sync;
-         sync_vals[wait_count] = 1;
-         wait_count++;
-         break;
-      case VN_SYNC_TYPE_WSI_SIGNALED:
-         signaled_count++;
-         break;
-      default:
-         unreachable("unexpected fence payload type");
-         break;
+      while (result == VK_NOT_READY) {
+         result = vn_remove_signaled_fences(device, fences, &fenceCount);
+         result = vn_update_sync_result(result, abs_timeout, &iter);
       }
-   }
 
-   VkResult result = VK_SUCCESS;
-   if (wait_count && (waitAll || !signaled_count)) {
-      const struct vn_renderer_wait wait = {
-         .wait_any = !waitAll,
-         .timeout = timeout,
-         .syncs = syncs,
-         .sync_values = sync_vals,
-         .sync_count = wait_count,
-      };
-      result = vn_renderer_wait(dev->instance->renderer, &wait);
-   }
-
-   if (syncs != local_syncs) {
-      vk_free(alloc, syncs);
-      vk_free(alloc, sync_vals);
+      if (fences != local_fences)
+         vk_free(alloc, fences);
+   } else {
+      while (result == VK_NOT_READY) {
+         result = vn_find_first_signaled_fence(device, pFences, fenceCount);
+         result = vn_update_sync_result(result, abs_timeout, &iter);
+      }
    }
 
    return vn_result(dev->instance, result);
@@ -934,34 +933,7 @@ vn_ImportFenceFdKHR(VkDevice device,
                     const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
 {
    struct vn_device *dev = vn_device_from_handle(device);
-   struct vn_fence *fence = vn_fence_from_handle(pImportFenceFdInfo->fence);
-   const bool sync_file = pImportFenceFdInfo->handleType ==
-                          VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
-   const int fd = pImportFenceFdInfo->fd;
-   struct vn_sync_payload *payload =
-      pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT
-         ? &fence->temporary
-         : &fence->permanent;
-
-   if (payload->type == VN_SYNC_TYPE_SYNC)
-      vn_renderer_sync_release(payload->sync);
-
-   VkResult result;
-   if (sync_file && fd < 0)
-      result = vn_renderer_sync_init_signaled(payload->sync);
-   else
-      result = vn_renderer_sync_init_syncobj(payload->sync, fd, sync_file);
-
-   if (result != VK_SUCCESS)
-      return vn_error(dev->instance, result);
-
-   payload->type = VN_SYNC_TYPE_SYNC;
-   fence->payload = payload;
-
-   if (fd >= 0)
-      close(fd);
-
-   return VK_SUCCESS;
+   return vn_error(dev->instance, VK_ERROR_UNKNOWN);
 }
 
 VkResult
@@ -970,21 +942,7 @@ vn_GetFenceFdKHR(VkDevice device,
                  int *pFd)
 {
    struct vn_device *dev = vn_device_from_handle(device);
-   struct vn_fence *fence = vn_fence_from_handle(pGetFdInfo->fence);
-   const bool sync_file =
-      pGetFdInfo->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
-   struct vn_sync_payload *payload = fence->payload;
-
-   assert(payload->type == VN_SYNC_TYPE_SYNC);
-   int fd = vn_renderer_sync_export_syncobj(payload->sync, sync_file);
-   if (fd < 0)
-      return vn_error(dev->instance, VK_ERROR_TOO_MANY_OBJECTS);
-
-   if (sync_file)
-      vn_ResetFences(device, 1, &pGetFdInfo->fence);
-
-   *pFd = fd;
-   return VK_SUCCESS;
+   return vn_error(dev->instance, VK_ERROR_UNKNOWN);
 }
 
 /* semaphore commands */



More information about the mesa-commit mailing list