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 (!q->maybe_available) { + struct timespec timeout; + timespec_get(&timeout, TIME_UTC); + timespec_add_msec(&timeout, &timeout, 2000); - if (vk_device_is_lost(&device->vk)) - return VK_ERROR_DEVICE_LOST; + VkResult result = VK_SUCCESS; - struct v3dv_query *q = &pool->queries[query]; - assert(q->bo && q->bo->map); + mtx_lock(&device->query_mutex); + while (!q->maybe_available) { + if (vk_device_is_lost(&device->vk)) { + result = VK_ERROR_DEVICE_LOST; + break; + } - 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"); + 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); - if (!v3dv_bo_wait(device, q->bo, 0xffffffffffffffffull)) - return vk_device_set_lost(&device->vk, "Query BO wait failed: %m"); - - *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); + if (!q->maybe_available) + return VK_NOT_READY; - struct v3dv_query *q = &pool->queries[query]; + if (query_type == VK_QUERY_TYPE_OCCLUSION && + !v3dv_bo_wait(device, q->bo, 0)) + return VK_NOT_READY; - 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"); - - *available = true; - } else { - *available = q->maybe_available; - } - - *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; }