| @@ -36,9 +36,12 @@ | |||
| #include "registers/a6xx.xml.h" | |||
| #include "nir/nir_builder.h" | |||
| #include "util/os_time.h" | |||
| #include "tu_cs.h" | |||
| #define NSEC_PER_SEC 1000000000ull | |||
| struct PACKED occlusion_query_slot { | |||
| uint64_t available; /* 0 when unavailable, 1 when available */ | |||
| uint64_t begin; | |||
| @@ -53,6 +56,13 @@ static uint64_t query_iova(struct tu_query_pool *pool, uint32_t query, | |||
| return pool->bo->iova + pool->stride * query + index * sizeof(uint64_t); | |||
| } | |||
| /* | |||
| * Returns a pointer to a given slot in a query pool. | |||
| */ | |||
| static void* slot_address(struct tu_query_pool *pool, uint32_t query) { | |||
| return (char*)pool->bo->map + query * pool->stride; | |||
| } | |||
| VkResult | |||
| tu_CreateQueryPool(VkDevice _device, | |||
| const VkQueryPoolCreateInfo *pCreateInfo, | |||
| @@ -123,6 +133,56 @@ tu_DestroyQueryPool(VkDevice _device, | |||
| vk_free2(&device->alloc, pAllocator, pool); | |||
| } | |||
| static bool | |||
| query_is_available(void *slot) { | |||
| return *(uint64_t*)slot; | |||
| } | |||
| /* Poll the availability status of a query up until a timeout. | |||
| */ | |||
| static VkResult | |||
| wait_for_available(struct tu_device *device, void *slot) { | |||
| uint64_t abs_timeout = os_time_get_absolute_timeout(5 * NSEC_PER_SEC); | |||
| while(os_time_get_nano() < abs_timeout) { | |||
| if (query_is_available(slot)) | |||
| return VK_SUCCESS; | |||
| } | |||
| return vk_error(device->instance, VK_TIMEOUT); | |||
| } | |||
| static VkResult | |||
| get_occlusion_query_pool_results(struct tu_device *device, | |||
| struct tu_query_pool *pool, | |||
| uint32_t firstQuery, | |||
| uint32_t queryCount, | |||
| size_t dataSize, | |||
| void *pData, | |||
| VkDeviceSize stride, | |||
| VkQueryResultFlags flags) { | |||
| // TODO: Support other flags. | |||
| assert(flags & VK_QUERY_RESULT_WAIT_BIT); | |||
| assert(!(flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)); | |||
| assert(!(flags & VK_QUERY_RESULT_PARTIAL_BIT)); | |||
| assert(dataSize >= stride * queryCount); | |||
| char *query_result = pData; | |||
| for (uint32_t i = 0; i < queryCount; i++) { | |||
| struct occlusion_query_slot *slot = slot_address(pool, firstQuery + i); | |||
| if (flags & VK_QUERY_RESULT_WAIT_BIT) { | |||
| VkResult result = wait_for_available(device, slot); | |||
| if (result != VK_SUCCESS) | |||
| return result; | |||
| } | |||
| if (flags & VK_QUERY_RESULT_64_BIT) { | |||
| *(uint64_t*)query_result = slot->end - slot->begin; | |||
| } else { | |||
| *(uint32_t*)query_result = slot->end - slot->begin; | |||
| } | |||
| query_result += stride; | |||
| } | |||
| return VK_SUCCESS; | |||
| } | |||
| VkResult | |||
| tu_GetQueryPoolResults(VkDevice _device, | |||
| VkQueryPool queryPool, | |||
| @@ -133,6 +193,21 @@ tu_GetQueryPoolResults(VkDevice _device, | |||
| VkDeviceSize stride, | |||
| VkQueryResultFlags flags) | |||
| { | |||
| TU_FROM_HANDLE(tu_device, device, _device); | |||
| TU_FROM_HANDLE(tu_query_pool, pool, queryPool); | |||
| assert(firstQuery + queryCount <= pool->size); | |||
| switch (pool->type) { | |||
| case VK_QUERY_TYPE_OCCLUSION: { | |||
| return get_occlusion_query_pool_results(device, pool, firstQuery, | |||
| queryCount, dataSize, pData, stride, flags); | |||
| } | |||
| case VK_QUERY_TYPE_PIPELINE_STATISTICS: | |||
| case VK_QUERY_TYPE_TIMESTAMP: | |||
| unreachable("Unimplemented query type"); | |||
| default: | |||
| assert(!"Invalid query type"); | |||
| } | |||
| return VK_SUCCESS; | |||
| } | |||