Mesa (main): v3dv: Add a condition variable for queries

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Apr 13 17:57:18 UTC 2022


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

Author: Jason Ekstrand <jason.ekstrand at collabora.com>
Date:   Mon Apr  4 10:25:15 2022 -0500

v3dv: Add a condition variable for queries

In order to properly wait for a query to be complete, we need to first
wait for the end query job to flush through on the queue.  Since query
end is always handled on the CPU, we can do this with a condition
variable.  The 2s timeout is taken from ANV.

Reviewed-by: Alejandro Piñeiro <apinheiro at igalia.com>
Reviewed-by: Iago Toral Quiroga <itoral at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15704>

---

 src/broadcom/vulkan/v3dv_device.c  |   7 ++
 src/broadcom/vulkan/v3dv_private.h |   6 ++
 src/broadcom/vulkan/v3dv_query.c   | 130 ++++++++++++++++++++-----------------
 src/broadcom/vulkan/v3dv_queue.c   |  10 +++
 4 files changed, 92 insertions(+), 61 deletions(-)

diff --git a/src/broadcom/vulkan/v3dv_device.c b/src/broadcom/vulkan/v3dv_device.c
index 52aaeeb756f..abc7073a0b8 100644
--- a/src/broadcom/vulkan/v3dv_device.c
+++ b/src/broadcom/vulkan/v3dv_device.c
@@ -1945,6 +1945,8 @@ v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
    device->pdevice = physical_device;
 
    mtx_init(&device->mutex, mtx_plain);
+   mtx_init(&device->query_mutex, mtx_plain);
+   cnd_init(&device->query_ended);
 
    result = queue_init(device, &device->queue,
                        pCreateInfo->pQueueCreateInfos, 0);
@@ -1998,6 +2000,8 @@ v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
 
 fail:
    destroy_device_syncs(device, physical_device->render_fd);
+   cnd_destroy(&device->query_ended);
+   mtx_destroy(&device->query_mutex);
    mtx_destroy(&device->mutex);
    vk_device_finish(&device->vk);
    vk_free(&device->vk.alloc, device);
@@ -2028,6 +2032,9 @@ v3dv_DestroyDevice(VkDevice _device,
     */
    v3dv_bo_cache_destroy(device);
 
+   cnd_destroy(&device->query_ended);
+   mtx_destroy(&device->query_mutex);
+
    vk_device_finish(&device->vk);
    vk_free2(&device->vk.alloc, pAllocator, device);
 }
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 894d0fb15a9..c0b313c4f77 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -479,6 +479,12 @@ struct v3dv_device {
    /* A mutex to prevent concurrent access to last_job_sync from the queue */
    mtx_t mutex;
 
+   /* Guards query->maybe_available and value for timestamps */
+   mtx_t query_mutex;
+
+   /* Signaled whenever a query is ended */
+   cnd_t query_ended;
+
    /* Resources used for meta operations */
    struct {
       mtx_t mtx;
diff --git a/src/broadcom/vulkan/v3dv_query.c b/src/broadcom/vulkan/v3dv_query.c
index 6102976dc68..60edfc52442 100644
--- a/src/broadcom/vulkan/v3dv_query.c
+++ b/src/broadcom/vulkan/v3dv_query.c
@@ -23,6 +23,8 @@
 
 #include "v3dv_private.h"
 
+#include "util/timespec.h"
+
 VKAPI_ATTR VkResult VKAPI_CALL
 v3dv_CreateQueryPool(VkDevice _device,
                      const VkQueryPoolCreateInfo *pCreateInfo,
@@ -138,74 +140,58 @@ write_query_result(void *dst, uint32_t idx, bool do_64bit, uint64_t value)
 }
 
 static VkResult
-get_occlusion_query_result(struct v3dv_device *device,
-                           struct v3dv_query_pool *pool,
-                           uint32_t query,
-                           bool do_wait,
-                           bool *available,
-                           uint64_t *value)
+query_wait_available(struct v3dv_device *device,
+                     struct v3dv_query *q,
+                     VkQueryType query_type)
 {
-   assert(pool && pool->query_type == VK_QUERY_TYPE_OCCLUSION);
-
-   if (vk_device_is_lost(&device->vk))
-      return VK_ERROR_DEVICE_LOST;
-
-   struct v3dv_query *q = &pool->queries[query];
-   assert(q->bo && q->bo->map);
-
-   if (do_wait) {
-      /* From the Vulkan 1.0 spec:
-       *
-       *    "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not
-       *     become available in a finite amount of time (e.g. due to not
-       *     issuing a query since the last reset), a VK_ERROR_DEVICE_LOST
-       *     error may occur."
-       */
-      if (!q->maybe_available)
-         return vk_device_set_lost(&device->vk, "Query unavailable");
+   if (!q->maybe_available) {
+      struct timespec timeout;
+      timespec_get(&timeout, TIME_UTC);
+      timespec_add_msec(&timeout, &timeout, 2000);
+
+      VkResult result = VK_SUCCESS;
+
+      mtx_lock(&device->query_mutex);
+      while (!q->maybe_available) {
+         if (vk_device_is_lost(&device->vk)) {
+            result = VK_ERROR_DEVICE_LOST;
+            break;
+         }
 
-      if (!v3dv_bo_wait(device, q->bo, 0xffffffffffffffffull))
-         return vk_device_set_lost(&device->vk, "Query BO wait failed: %m");
+         int ret = cnd_timedwait(&device->query_ended,
+                                 &device->query_mutex,
+                                 &timeout);
+         if (ret != thrd_success) {
+            mtx_unlock(&device->query_mutex);
+            result = vk_device_set_lost(&device->vk, "Query wait failed");
+            break;
+         }
+      }
+      mtx_unlock(&device->query_mutex);
 
-      *available = true;
-   } else {
-      *available = q->maybe_available && v3dv_bo_wait(device, q->bo, 0);
+      if (result != VK_SUCCESS)
+         return result;
    }
 
-   const uint8_t *query_addr = ((uint8_t *) q->bo->map) + q->offset;
-   *value = (uint64_t) *((uint32_t *)query_addr);
+   if (query_type == VK_QUERY_TYPE_OCCLUSION &&
+       !v3dv_bo_wait(device, q->bo, 0xffffffffffffffffull))
+      return vk_device_set_lost(&device->vk, "Query BO wait failed: %m");
+
    return VK_SUCCESS;
 }
 
 static VkResult
-get_timestamp_query_result(struct v3dv_device *device,
-                           struct v3dv_query_pool *pool,
-                           uint32_t query,
-                           bool do_wait,
-                           bool *available,
-                           uint64_t *value)
+query_is_available(struct v3dv_device *device,
+                   struct v3dv_query *q,
+                   VkQueryType query_type)
 {
-   assert(pool && pool->query_type == VK_QUERY_TYPE_TIMESTAMP);
-
-   struct v3dv_query *q = &pool->queries[query];
-
-   if (do_wait) {
-      /* From the Vulkan 1.0 spec:
-       *
-       *    "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not
-       *     become available in a finite amount of time (e.g. due to not
-       *     issuing a query since the last reset), a VK_ERROR_DEVICE_LOST
-       *     error may occur."
-       */
-      if (!q->maybe_available)
-         return vk_device_set_lost(&device->vk, "Query unavailable");
+   if (!q->maybe_available)
+      return VK_NOT_READY;
 
-      *available = true;
-   } else {
-      *available = q->maybe_available;
-   }
+   if (query_type == VK_QUERY_TYPE_OCCLUSION &&
+       !v3dv_bo_wait(device, q->bo, 0))
+      return VK_NOT_READY;
 
-   *value = q->value;
    return VK_SUCCESS;
 }
 
@@ -217,13 +203,31 @@ get_query_result(struct v3dv_device *device,
                  bool *available,
                  uint64_t *value)
 {
+   struct v3dv_query *q = &pool->queries[query];
+
+   if (do_wait) {
+      VkResult result = query_wait_available(device, q, pool->query_type);
+      if (result != VK_SUCCESS)
+         return result;
+
+      *available = true;
+   } else {
+      VkResult result = query_is_available(device, q, pool->query_type);
+      assert(result == VK_SUCCESS || result == VK_NOT_READY);
+      *available = (result == VK_SUCCESS);
+   }
+
    switch (pool->query_type) {
-   case VK_QUERY_TYPE_OCCLUSION:
-      return get_occlusion_query_result(device, pool, query, do_wait,
-                                        available, value);
+   case VK_QUERY_TYPE_OCCLUSION: {
+      const uint8_t *query_addr = ((uint8_t *) q->bo->map) + q->offset;
+      *value = (uint64_t) *((uint32_t *)query_addr);
+      return VK_SUCCESS;
+   }
+
    case VK_QUERY_TYPE_TIMESTAMP:
-      return get_timestamp_query_result(device, pool, query, do_wait,
-                                        available, value);
+      *value = q->value;
+      return VK_SUCCESS;
+
    default:
       unreachable("Unsupported query type");
    }
@@ -361,6 +365,8 @@ v3dv_reset_query_pools(struct v3dv_device *device,
                        uint32_t first,
                        uint32_t count)
 {
+   mtx_lock(&device->query_mutex);
+
    for (uint32_t i = first; i < first + count; i++) {
       assert(i < pool->query_count);
       struct v3dv_query *q = &pool->queries[i];
@@ -379,6 +385,8 @@ v3dv_reset_query_pools(struct v3dv_device *device,
          unreachable("Unsupported query type");
       }
    }
+
+   mtx_unlock(&device->query_mutex);
 }
 
 VKAPI_ATTR void VKAPI_CALL
diff --git a/src/broadcom/vulkan/v3dv_queue.c b/src/broadcom/vulkan/v3dv_queue.c
index cd1018efd72..51d2ae8cf56 100644
--- a/src/broadcom/vulkan/v3dv_queue.c
+++ b/src/broadcom/vulkan/v3dv_queue.c
@@ -180,6 +180,8 @@ handle_reset_query_cpu_job(struct v3dv_job *job)
 static VkResult
 handle_end_query_cpu_job(struct v3dv_job *job)
 {
+   mtx_lock(&job->device->query_mutex);
+
    struct v3dv_end_query_cpu_job_info *info = &job->cpu.query_end;
    for (uint32_t i = 0; i < info->count; i++) {
       assert(info->query + i < info->pool->query_count);
@@ -187,6 +189,9 @@ handle_end_query_cpu_job(struct v3dv_job *job)
       query->maybe_available = true;
    }
 
+   cnd_broadcast(&job->device->query_ended);
+   mtx_unlock(&job->device->query_mutex);
+
    return VK_SUCCESS;
 }
 
@@ -546,6 +551,8 @@ handle_timestamp_query_cpu_job(struct v3dv_job *job)
    /* Wait for completion of all work queued before the timestamp query */
    v3dv_QueueWaitIdle(v3dv_queue_to_handle(&job->device->queue));
 
+   mtx_lock(&job->device->query_mutex);
+
    /* Compute timestamp */
    struct timespec t;
    clock_gettime(CLOCK_MONOTONIC, &t);
@@ -558,6 +565,9 @@ handle_timestamp_query_cpu_job(struct v3dv_job *job)
          query->value = t.tv_sec * 1000000000ull + t.tv_nsec;
    }
 
+   cnd_broadcast(&job->device->query_ended);
+   mtx_unlock(&job->device->query_mutex);
+
    return VK_SUCCESS;
 }
 



More information about the mesa-commit mailing list