Mesa (main): panvk: Add vkEvents support

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jul 5 14:13:29 UTC 2021


Module: Mesa
Branch: main
Commit: 1e23004600c3b29776c2a36854b1a1c8756d5f81
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=1e23004600c3b29776c2a36854b1a1c8756d5f81

Author: Tomeu Vizoso <tomeu.vizoso at collabora.com>
Date:   Fri Jun  4 10:25:24 2021 +0200

panvk: Add vkEvents support

Use syncobjs to implement vkEvents (as suggested by Boris).

Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11709>

---

 src/panfrost/vulkan/panvk_cmd_buffer.c | 117 +++++++++++++++++++++--
 src/panfrost/vulkan/panvk_device.c     | 167 ++++++++++++++++++++++++++++++---
 src/panfrost/vulkan/panvk_private.h    |  13 +++
 3 files changed, 277 insertions(+), 20 deletions(-)

diff --git a/src/panfrost/vulkan/panvk_cmd_buffer.c b/src/panfrost/vulkan/panvk_cmd_buffer.c
index 654a06f10e3..3da978b4837 100644
--- a/src/panfrost/vulkan/panvk_cmd_buffer.c
+++ b/src/panfrost/vulkan/panvk_cmd_buffer.c
@@ -49,6 +49,9 @@ panvk_reset_cmdbuf(struct panvk_cmd_buffer *cmdbuf)
       util_dynarray_fini(&batch->jobs);
       if (!pan_is_bifrost(pdev))
          panfrost_bo_unreference(batch->tiler.ctx.midgard.polygon_list);
+
+      util_dynarray_fini(&batch->event_ops);
+
       vk_free(&cmdbuf->pool->alloc, batch);
    }
 
@@ -119,6 +122,9 @@ panvk_destroy_cmdbuf(struct panvk_cmd_buffer *cmdbuf)
       util_dynarray_fini(&batch->jobs);
       if (!pan_is_bifrost(pdev))
          panfrost_bo_unreference(batch->tiler.ctx.midgard.polygon_list);
+
+      util_dynarray_fini(&batch->event_ops);
+
       vk_free(&cmdbuf->pool->alloc, batch);
    }
 
@@ -690,6 +696,7 @@ panvk_CmdBeginRenderPass2(VkCommandBuffer commandBuffer,
                                    sizeof(*cmdbuf->state.batch), 8,
                                    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
    util_dynarray_init(&cmdbuf->state.batch->jobs, NULL);
+   util_dynarray_init(&cmdbuf->state.batch->event_ops, NULL);
    cmdbuf->state.clear = vk_zalloc(&cmdbuf->pool->alloc,
                                    sizeof(*cmdbuf->state.clear) *
                                    pRenderPassBegin->clearValueCount, 8,
@@ -769,17 +776,31 @@ panvk_cmd_get_midgard_polygon_list(struct panvk_cmd_buffer *cmdbuf,
 void
 panvk_cmd_close_batch(struct panvk_cmd_buffer *cmdbuf)
 {
-   assert(cmdbuf->state.batch);
+   struct panvk_batch *batch = cmdbuf->state.batch;
 
-   if (!cmdbuf->state.batch->fragment_job &&
-       !cmdbuf->state.batch->scoreboard.first_job) {
-      vk_free(&cmdbuf->pool->alloc, cmdbuf->state.batch);
+   assert(batch);
+
+   if (!batch->fragment_job && !batch->scoreboard.first_job) {
+      if (util_dynarray_num_elements(&batch->event_ops, struct panvk_event_op) == 0) {
+         /* Content-less batch, let's drop it */
+         vk_free(&cmdbuf->pool->alloc, batch);
+      } else {
+         /* Batch has no jobs but is needed for synchronization, let's add a
+          * NULL job so the SUBMIT ioctl doesn't choke on it.
+          */
+         struct panfrost_ptr ptr = pan_pool_alloc_desc(&cmdbuf->desc_pool.base,
+                                                       JOB_HEADER);
+         util_dynarray_append(&batch->jobs, void *, ptr.cpu);
+         panfrost_add_job(&cmdbuf->desc_pool.base, &batch->scoreboard,
+                          MALI_JOB_TYPE_NULL, false, false, 0, 0,
+                          &ptr, false);
+         list_addtail(&batch->node, &cmdbuf->batches);
+      }
       cmdbuf->state.batch = NULL;
       return;
    }
 
    struct panfrost_device *pdev = &cmdbuf->device->physical_device->pdev;
-   struct panvk_batch *batch = cmdbuf->state.batch;
 
    list_addtail(&cmdbuf->state.batch->node, &cmdbuf->batches);
 
@@ -1480,12 +1501,79 @@ panvk_CmdPipelineBarrier(VkCommandBuffer commandBuffer,
    }
 }
 
+static void
+panvk_add_set_event_operation(struct panvk_cmd_buffer *cmdbuf,
+                              struct panvk_event *event,
+                              enum panvk_event_op_type type)
+{
+   struct panvk_event_op op = {
+      .type = type,
+      .event = event,
+   };
+
+   if (cmdbuf->state.batch == NULL) {
+      /* No open batch, let's create a new one so this operation happens in
+       * the right order.
+       */
+      panvk_cmd_open_batch(cmdbuf);
+      util_dynarray_append(&cmdbuf->state.batch->event_ops,
+                           struct panvk_event_op,
+                           op);
+      panvk_cmd_close_batch(cmdbuf);
+   } else {
+      /* Let's close the current batch so the operation executes before any
+       * future commands.
+       */
+      util_dynarray_append(&cmdbuf->state.batch->event_ops,
+                           struct panvk_event_op,
+                           op);
+      panvk_cmd_close_batch(cmdbuf);
+      panvk_cmd_open_batch(cmdbuf);
+   }
+}
+
+static void
+panvk_add_wait_event_operation(struct panvk_cmd_buffer *cmdbuf,
+                               struct panvk_event *event)
+{
+   struct panvk_event_op op = {
+      .type = PANVK_EVENT_OP_WAIT,
+      .event = event,
+   };
+
+   if (cmdbuf->state.batch == NULL) {
+      /* No open batch, let's create a new one and have it wait for this event. */
+      panvk_cmd_open_batch(cmdbuf);
+      util_dynarray_append(&cmdbuf->state.batch->event_ops,
+                           struct panvk_event_op,
+                           op);
+   } else {
+      /* Let's close the current batch so any future commands wait on the
+       * event signal operation.
+       */
+      if (cmdbuf->state.batch->fragment_job ||
+          cmdbuf->state.batch->scoreboard.first_job) {
+         panvk_cmd_close_batch(cmdbuf);
+         panvk_cmd_open_batch(cmdbuf);
+      }
+      util_dynarray_append(&cmdbuf->state.batch->event_ops,
+                           struct panvk_event_op,
+                           op);
+   }
+}
+
 void
 panvk_CmdSetEvent(VkCommandBuffer commandBuffer,
                   VkEvent _event,
                   VkPipelineStageFlags stageMask)
 {
-   panvk_stub();
+   VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
+   VK_FROM_HANDLE(panvk_event, event, _event);
+
+   /* vkCmdSetEvent cannot be called inside a render pass */
+   assert(cmdbuf->state.pass == NULL);
+
+   panvk_add_set_event_operation(cmdbuf, event, PANVK_EVENT_OP_SET);
 }
 
 void
@@ -1493,7 +1581,13 @@ panvk_CmdResetEvent(VkCommandBuffer commandBuffer,
                     VkEvent _event,
                     VkPipelineStageFlags stageMask)
 {
-   panvk_stub();
+   VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
+   VK_FROM_HANDLE(panvk_event, event, _event);
+
+   /* vkCmdResetEvent cannot be called inside a render pass */
+   assert(cmdbuf->state.pass == NULL);
+
+   panvk_add_set_event_operation(cmdbuf, event, PANVK_EVENT_OP_RESET);
 }
 
 void
@@ -1509,7 +1603,14 @@ panvk_CmdWaitEvents(VkCommandBuffer commandBuffer,
                     uint32_t imageMemoryBarrierCount,
                     const VkImageMemoryBarrier *pImageMemoryBarriers)
 {
-   panvk_stub();
+   VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
+
+   assert(eventCount > 0);
+
+   for (uint32_t i = 0; i < eventCount; i++) {
+      VK_FROM_HANDLE(panvk_event, event, pEvents[i]);
+      panvk_add_wait_event_operation(cmdbuf, event);
+   }
 }
 
 void
diff --git a/src/panfrost/vulkan/panvk_device.c b/src/panfrost/vulkan/panvk_device.c
index ddd146cb244..4a0dbd71675 100644
--- a/src/panfrost/vulkan/panvk_device.c
+++ b/src/panfrost/vulkan/panvk_device.c
@@ -1186,6 +1186,58 @@ panvk_queue_transfer_sync(struct panvk_queue *queue, uint32_t syncobj)
    close(handle.fd);
 }
 
+static void
+panvk_add_wait_event_syncobjs(struct panvk_batch *batch, uint32_t *in_fences, unsigned *nr_in_fences)
+{
+   util_dynarray_foreach(&batch->event_ops, struct panvk_event_op, op) {
+      switch (op->type) {
+      case PANVK_EVENT_OP_SET:
+         /* Nothing to do yet */
+         break;
+      case PANVK_EVENT_OP_RESET:
+         /* Nothing to do yet */
+         break;
+      case PANVK_EVENT_OP_WAIT:
+         in_fences[*nr_in_fences++] = op->event->syncobj;
+         break;
+      default:
+         unreachable("bad panvk_event_op type\n");
+      }
+   }
+}
+
+static void
+panvk_signal_event_syncobjs(struct panvk_queue *queue, struct panvk_batch *batch)
+{
+   const struct panfrost_device *pdev = &queue->device->physical_device->pdev;
+
+   util_dynarray_foreach(&batch->event_ops, struct panvk_event_op, op) {
+      switch (op->type) {
+      case PANVK_EVENT_OP_SET: {
+         panvk_queue_transfer_sync(queue, op->event->syncobj);
+         break;
+      }
+      case PANVK_EVENT_OP_RESET: {
+         struct panvk_event *event = op->event;
+
+         struct drm_syncobj_array objs = {
+            .handles = (uint64_t) (uintptr_t) &event->syncobj,
+            .count_handles = 1
+         };
+
+         int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_RESET, &objs);
+         assert(!ret);
+         break;
+      }
+      case PANVK_EVENT_OP_WAIT:
+         /* Nothing left to do */
+         break;
+      default:
+         unreachable("bad panvk_event_op type\n");
+      }
+   }
+}
+
 VkResult
 panvk_QueueSubmit(VkQueue _queue,
                   uint32_t submitCount,
@@ -1198,14 +1250,14 @@ panvk_QueueSubmit(VkQueue _queue,
 
    for (uint32_t i = 0; i < submitCount; ++i) {
       const VkSubmitInfo *submit = pSubmits + i;
-      unsigned nr_in_fences = submit->waitSemaphoreCount + 1;
-      uint32_t in_fences[nr_in_fences];
+      unsigned nr_semaphores = submit->waitSemaphoreCount + 1;
+      uint32_t semaphores[nr_semaphores];
       
-      in_fences[0] = queue->sync;
+      semaphores[0] = queue->sync;
       for (unsigned i = 0; i < submit->waitSemaphoreCount; i++) {
          VK_FROM_HANDLE(panvk_semaphore, sem, submit->pWaitSemaphores[i]);
 
-         in_fences[i + 1] = sem->syncobj.temporary ? : sem->syncobj.permanent;
+         semaphores[i + 1] = sem->syncobj.temporary ? : sem->syncobj.permanent;
       }
 
       for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {
@@ -1250,7 +1302,20 @@ panvk_QueueSubmit(VkQueue _queue,
 
             bos[bo_idx++] = pdev->sample_positions->gem_handle;
             assert(bo_idx == nr_bos);
+
+            unsigned nr_in_fences = 0;
+            unsigned max_wait_event_syncobjs =
+               util_dynarray_num_elements(&batch->event_ops,
+                                          struct panvk_event_op);
+            uint32_t in_fences[nr_semaphores + max_wait_event_syncobjs];
+            memcpy(in_fences, semaphores, nr_semaphores * sizeof(*in_fences));
+            nr_in_fences += nr_semaphores;
+
+            panvk_add_wait_event_syncobjs(batch, in_fences, &nr_in_fences);
+
             panvk_queue_submit_batch(queue, batch, bos, nr_bos, in_fences, nr_in_fences);
+
+            panvk_signal_event_syncobjs(queue, batch);
          }
       }
 
@@ -1634,7 +1699,25 @@ panvk_CreateEvent(VkDevice _device,
                   const VkAllocationCallbacks *pAllocator,
                   VkEvent *pEvent)
 {
-   panvk_stub();
+   VK_FROM_HANDLE(panvk_device, device, _device);
+   const struct panfrost_device *pdev = &device->physical_device->pdev;
+   struct panvk_event *event =
+      vk_object_zalloc(&device->vk, pAllocator, sizeof(*event),
+                       VK_OBJECT_TYPE_EVENT);
+   if (!event)
+      return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   struct drm_syncobj_create create = {
+      .flags = 0,
+   };
+
+   int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
+   if (ret)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   event->syncobj = create.handle;
+   *pEvent = panvk_event_to_handle(event);
+
    return VK_SUCCESS;
 }
 
@@ -1643,28 +1726,88 @@ panvk_DestroyEvent(VkDevice _device,
                    VkEvent _event,
                    const VkAllocationCallbacks *pAllocator)
 {
-   panvk_stub();
+   VK_FROM_HANDLE(panvk_device, device, _device);
+   VK_FROM_HANDLE(panvk_event, event, _event);
+   const struct panfrost_device *pdev = &device->physical_device->pdev;
+
+   if (!event)
+      return;
+
+   struct drm_syncobj_destroy destroy = { .handle = event->syncobj };
+   drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &destroy);
+
+   vk_object_free(&device->vk, pAllocator, event);
 }
 
 VkResult
 panvk_GetEventStatus(VkDevice _device, VkEvent _event)
 {
-   panvk_stub();
-   return VK_EVENT_RESET;
+   VK_FROM_HANDLE(panvk_device, device, _device);
+   VK_FROM_HANDLE(panvk_event, event, _event);
+   const struct panfrost_device *pdev = &device->physical_device->pdev;
+   bool signaled;
+
+   struct drm_syncobj_wait wait = {
+      .handles = (uintptr_t) &event->syncobj,
+      .count_handles = 1,
+      .timeout_nsec = 0,
+      .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
+   };
+
+   int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_WAIT, &wait);
+   if (ret) {
+      if (errno == ETIME)
+         signaled = false;
+      else {
+         assert(0);
+         return VK_ERROR_DEVICE_LOST; /* TODO */
+      }
+   } else
+      signaled = true;
+
+   return signaled ? VK_EVENT_SET : VK_EVENT_RESET;
 }
 
 VkResult
 panvk_SetEvent(VkDevice _device, VkEvent _event)
 {
-   panvk_stub();
-   return VK_SUCCESS;
+   VK_FROM_HANDLE(panvk_device, device, _device);
+   VK_FROM_HANDLE(panvk_event, event, _event);
+   const struct panfrost_device *pdev = &device->physical_device->pdev;
+
+   struct drm_syncobj_array objs = {
+      .handles = (uint64_t) (uintptr_t) &event->syncobj,
+      .count_handles = 1
+   };
+
+   /* This is going to just replace the fence for this syncobj with one that
+    * is already in signaled state. This won't be a problem because the spec
+    * mandates that the event will have been set before the vkCmdWaitEvents
+    * command executes.
+    * https://www.khronos.org/registry/vulkan/specs/1.2/html/chap6.html#commandbuffers-submission-progress
+    */
+   if (drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &objs))
+      return VK_ERROR_DEVICE_LOST;
+
+  return VK_SUCCESS;
 }
 
 VkResult
 panvk_ResetEvent(VkDevice _device, VkEvent _event)
 {
-   panvk_stub();
-   return VK_SUCCESS;
+   VK_FROM_HANDLE(panvk_device, device, _device);
+   VK_FROM_HANDLE(panvk_event, event, _event);
+   const struct panfrost_device *pdev = &device->physical_device->pdev;
+
+   struct drm_syncobj_array objs = {
+      .handles = (uint64_t) (uintptr_t) &event->syncobj,
+      .count_handles = 1
+   };
+
+   if (drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_RESET, &objs))
+      return VK_ERROR_DEVICE_LOST;
+
+  return VK_SUCCESS;
 }
 
 VkResult
diff --git a/src/panfrost/vulkan/panvk_private.h b/src/panfrost/vulkan/panvk_private.h
index e644c0e1ca0..b4e331fb6b9 100644
--- a/src/panfrost/vulkan/panvk_private.h
+++ b/src/panfrost/vulkan/panvk_private.h
@@ -252,6 +252,7 @@ panvk_device_is_lost(struct panvk_device *device)
 struct panvk_batch {
    struct list_head node;
    struct util_dynarray jobs;
+   struct util_dynarray event_ops;
    struct pan_scoreboard scoreboard;
    struct {
       const struct panvk_framebuffer *info;
@@ -280,6 +281,17 @@ struct panvk_syncobj {
    uint32_t permanent, temporary;
 };
 
+enum panvk_event_op_type {
+   PANVK_EVENT_OP_SET,
+   PANVK_EVENT_OP_RESET,
+   PANVK_EVENT_OP_WAIT,
+};
+
+struct panvk_event_op {
+   enum panvk_event_op_type type;
+   struct panvk_event *event;
+};
+
 struct panvk_fence {
    struct vk_object_base base;
    struct panvk_syncobj syncobj;
@@ -668,6 +680,7 @@ panvk_pack_color(struct panvk_clear_value *out,
 
 struct panvk_event {
    struct vk_object_base base;
+   uint32_t syncobj;
 };
 
 struct panvk_shader_module {



More information about the mesa-commit mailing list