v3dv: simplify handling of no-op jobs
authorIago Toral Quiroga <itoral@igalia.com>
Thu, 16 Apr 2020 10:35:06 +0000 (12:35 +0200)
committerMarge Bot <eric+marge@anholt.net>
Tue, 13 Oct 2020 21:21:29 +0000 (21:21 +0000)
Avoid creating (and destroying) no-op jobs more than once. Instead,
cache the job and use it every time we need to submit one.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>

src/broadcom/vulkan/v3dv_device.c
src/broadcom/vulkan/v3dv_private.h
src/broadcom/vulkan/v3dv_queue.c

index db6b6ab..6125074 100644 (file)
@@ -1026,17 +1026,12 @@ queue_init(struct v3dv_device *device, struct v3dv_queue *queue)
    queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
    queue->device = device;
    queue->flags = 0;
-   list_inithead(&queue->noop_jobs);
    return VK_SUCCESS;
 }
 
 static void
 queue_finish(struct v3dv_queue *queue)
 {
-   /* We wait for the device to be idle before finishing the queue, so
-    * this should any pending jobs.
-    */
-   v3dv_queue_destroy_completed_noop_jobs(queue);
 }
 
 static void
index 99a9ee2..e27f3af 100644 (file)
@@ -206,18 +206,8 @@ struct v3dv_queue {
    struct v3dv_device *device;
 
    VkDeviceQueueCreateFlags flags;
-
-   /* When the client submits to the queue without a command buffer the queue
-    * needs to create and submit a no-op job and it is then responsible from
-    * destroying it once it has completed execution. This list keeps references
-    * to all no-op jobs in flight so we can do that.
-    */
-   struct list_head noop_jobs;
 };
 
-void v3dv_queue_destroy_completed_noop_jobs(struct v3dv_queue *queue);
-
-
 struct v3dv_meta_color_clear_pipeline {
    VkPipeline pipeline;
    VkRenderPass pass;
@@ -672,14 +662,6 @@ struct v3dv_job {
    enum v3dv_ez_state ez_state;
    enum v3dv_ez_state first_ez_state;
 
-   /* Typically, the client is responsible for handling the life-time of
-    * command buffers by using fences to tell when they are no longer in
-    * use by the GPU, however, when the jobs that are submitted to the GPU
-    * are created internally by the driver (for example when we need to
-    * submit no-op jobs), then it is our responsibility to do that.
-    */
-   struct v3dv_fence *fence;
-
    /* Number of draw calls recorded into the job */
    uint32_t draw_count;
 
index 80beaca..8d2dc80 100644 (file)
@@ -403,93 +403,21 @@ queue_create_noop_job(struct v3dv_queue *queue, struct v3dv_job **job)
    return VK_SUCCESS;
 }
 
-void
-v3dv_queue_destroy_completed_noop_jobs(struct v3dv_queue *queue)
-{
-   struct v3dv_device *device = queue->device;
-   VkDevice _device = v3dv_device_to_handle(device);
-
-   list_for_each_entry_safe(struct v3dv_job, job,
-                            &queue->noop_jobs, list_link) {
-      assert(job->fence);
-      if (!drmSyncobjWait(device->render_fd, &job->fence->sync, 1, 0, 0, NULL)) {
-         v3dv_job_destroy(job);
-         v3dv_DestroyFence(_device, v3dv_fence_to_handle(job->fence), NULL);
-      }
-   }
-}
-
 static VkResult
 queue_submit_noop_job(struct v3dv_queue *queue, const VkSubmitInfo *pSubmit)
 {
-   VkResult result;
-   bool can_destroy_job = true;
-
-   struct v3dv_device *device = queue->device;
-   VkDevice _device = v3dv_device_to_handle(device);
-
-   /* Create noop job */
-   struct v3dv_job *job;
-   result = queue_create_noop_job(queue, &job);
-   if (result != VK_SUCCESS)
-      goto fail_job;
-
-   /* Create a fence for the job */
-   VkFence _fence;
-   VkFenceCreateInfo fence_info = {
-      .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
-      .pNext = NULL,
-      .flags = 0
-   };
-
-   result = v3dv_CreateFence(_device, &fence_info, NULL, &_fence);
-   if (result != VK_SUCCESS)
-      goto fail_fence;
-
-   /* Submit the job */
-   result = queue_submit_job(queue, job, pSubmit->waitSemaphoreCount > 0);
-   if (result != VK_SUCCESS)
-      goto fail_submit;
-
-   list_addtail(&job->list_link, &queue->noop_jobs);
-
-   /* At this point we have submitted the job for execution and we can no
-    * longer destroy it until we know it has completed execution on the GPU.
+   /* VkQueue host access is externally synchronized so we don't need to lock
+    * here for the static variable.
     */
-   can_destroy_job = false;
+   static struct v3dv_job *noop_job = NULL;
 
-   /* Bind a fence to the job we have just submitted so we can poll if the job
-    * has completed.
-    */
-   if (process_fence_to_signal(device, _fence) != VK_SUCCESS) {
-      /* If we could not bind the fence, then we need to do a sync wait so
-       * we don't leak the job. If the sync wait also fails, then we are
-       * out of options.
-       */
-      int ret = drmSyncobjWait(device->render_fd,
-                               &device->last_job_sync, 1, INT64_MAX, 0, NULL);
-      if (!ret)
-         can_destroy_job = true;
-      else
-         result = vk_error(device->instance, VK_ERROR_DEVICE_LOST);
-
-      goto fail_signal_fence;
+   if (!noop_job) {
+      VkResult result = queue_create_noop_job(queue, &noop_job);
+      if (result != VK_SUCCESS)
+         return result;
    }
 
-   job->fence = v3dv_fence_from_handle(_fence);
-
-   return result;
-
-fail_signal_fence:
-fail_submit:
-   v3dv_DestroyFence(_device, _fence, NULL);
-
-fail_fence:
-   if (can_destroy_job)
-      v3dv_job_destroy(job);
-
-fail_job:
-   return result;
+   return queue_submit_job(queue, noop_job, pSubmit->waitSemaphoreCount > 0);
 }
 
 static VkResult
@@ -557,8 +485,6 @@ v3dv_QueueSubmit(VkQueue _queue,
 {
    V3DV_FROM_HANDLE(v3dv_queue, queue, _queue);
 
-   v3dv_queue_destroy_completed_noop_jobs(queue);
-
    VkResult result = VK_SUCCESS;
    for (uint32_t i = 0; i < submitCount; i++) {
       result = queue_submit_cmd_buffer_batch(queue, &pSubmits[i], fence);