Path: blob/21.2-virgl/src/broadcom/vulkan/v3dv_query.c
4560 views
/*1* Copyright © 2020 Raspberry Pi2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "v3dv_private.h"2425VKAPI_ATTR VkResult VKAPI_CALL26v3dv_CreateQueryPool(VkDevice _device,27const VkQueryPoolCreateInfo *pCreateInfo,28const VkAllocationCallbacks *pAllocator,29VkQueryPool *pQueryPool)30{31V3DV_FROM_HANDLE(v3dv_device, device, _device);3233assert(pCreateInfo->queryType == VK_QUERY_TYPE_OCCLUSION ||34pCreateInfo->queryType == VK_QUERY_TYPE_TIMESTAMP);35assert(pCreateInfo->queryCount > 0);3637struct v3dv_query_pool *pool =38vk_object_zalloc(&device->vk, pAllocator, sizeof(*pool),39VK_OBJECT_TYPE_QUERY_POOL);40if (pool == NULL)41return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);4243pool->query_type = pCreateInfo->queryType;44pool->query_count = pCreateInfo->queryCount;4546VkResult result;4748const uint32_t pool_bytes = sizeof(struct v3dv_query) * pool->query_count;49pool->queries = vk_alloc2(&device->vk.alloc, pAllocator, pool_bytes, 8,50VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);51if (pool->queries == NULL) {52result = vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);53goto fail;54}5556if (pool->query_type == VK_QUERY_TYPE_OCCLUSION) {57/* The hardware allows us to setup groups of 16 queries in consecutive58* 4-byte addresses, requiring only that each group of 16 queries is59* aligned to a 1024 byte boundary.60*/61const uint32_t query_groups = DIV_ROUND_UP(pool->query_count, 16);62const uint32_t bo_size = query_groups * 1024;63pool->bo = v3dv_bo_alloc(device, bo_size, "query", true);64if (!pool->bo) {65result = vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);66goto fail;67}68if (!v3dv_bo_map(device, pool->bo, bo_size)) {69result = vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);70goto fail;71}72}7374uint32_t i;75for (i = 0; i < pool->query_count; i++) {76pool->queries[i].maybe_available = false;77switch (pool->query_type) {78case VK_QUERY_TYPE_OCCLUSION: {79const uint32_t query_group = i / 16;80const uint32_t query_offset = query_group * 1024 + (i % 16) * 4;81pool->queries[i].bo = pool->bo;82pool->queries[i].offset = query_offset;83break;84}85case VK_QUERY_TYPE_TIMESTAMP:86pool->queries[i].value = 0;87break;88default:89unreachable("Unsupported query type");90}91}9293*pQueryPool = v3dv_query_pool_to_handle(pool);9495return VK_SUCCESS;9697fail:98if (pool->bo)99v3dv_bo_free(device, pool->bo);100if (pool->queries)101vk_free2(&device->vk.alloc, pAllocator, pool->queries);102vk_object_free(&device->vk, pAllocator, pool);103104return result;105}106107VKAPI_ATTR void VKAPI_CALL108v3dv_DestroyQueryPool(VkDevice _device,109VkQueryPool queryPool,110const VkAllocationCallbacks *pAllocator)111{112V3DV_FROM_HANDLE(v3dv_device, device, _device);113V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);114115if (!pool)116return;117118if (pool->bo)119v3dv_bo_free(device, pool->bo);120121if (pool->queries)122vk_free2(&device->vk.alloc, pAllocator, pool->queries);123124vk_object_free(&device->vk, pAllocator, pool);125}126127static void128write_query_result(void *dst, uint32_t idx, bool do_64bit, uint64_t value)129{130if (do_64bit) {131uint64_t *dst64 = (uint64_t *) dst;132dst64[idx] = value;133} else {134uint32_t *dst32 = (uint32_t *) dst;135dst32[idx] = (uint32_t) value;136}137}138139static uint64_t140get_occlusion_query_result(struct v3dv_device *device,141struct v3dv_query_pool *pool,142uint32_t query,143bool do_wait,144bool *available)145{146assert(pool && pool->query_type == VK_QUERY_TYPE_OCCLUSION);147148struct v3dv_query *q = &pool->queries[query];149assert(q->bo && q->bo->map);150151if (do_wait) {152/* From the Vulkan 1.0 spec:153*154* "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not155* become available in a finite amount of time (e.g. due to not156* issuing a query since the last reset), a VK_ERROR_DEVICE_LOST157* error may occur."158*/159if (!q->maybe_available)160return vk_error(device->instance, VK_ERROR_DEVICE_LOST);161162if (!v3dv_bo_wait(device, q->bo, 0xffffffffffffffffull))163return vk_error(device->instance, VK_ERROR_DEVICE_LOST);164165*available = true;166} else {167*available = q->maybe_available && v3dv_bo_wait(device, q->bo, 0);168}169170const uint8_t *query_addr = ((uint8_t *) q->bo->map) + q->offset;171return (uint64_t) *((uint32_t *)query_addr);172}173174static uint64_t175get_timestamp_query_result(struct v3dv_device *device,176struct v3dv_query_pool *pool,177uint32_t query,178bool do_wait,179bool *available)180{181assert(pool && pool->query_type == VK_QUERY_TYPE_TIMESTAMP);182183struct v3dv_query *q = &pool->queries[query];184185if (do_wait) {186/* From the Vulkan 1.0 spec:187*188* "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not189* become available in a finite amount of time (e.g. due to not190* issuing a query since the last reset), a VK_ERROR_DEVICE_LOST191* error may occur."192*/193if (!q->maybe_available)194return vk_error(device->instance, VK_ERROR_DEVICE_LOST);195196*available = true;197} else {198*available = q->maybe_available;199}200201return q->value;202}203204static uint64_t205get_query_result(struct v3dv_device *device,206struct v3dv_query_pool *pool,207uint32_t query,208bool do_wait,209bool *available)210{211switch (pool->query_type) {212case VK_QUERY_TYPE_OCCLUSION:213return get_occlusion_query_result(device, pool, query, do_wait, available);214case VK_QUERY_TYPE_TIMESTAMP:215return get_timestamp_query_result(device, pool, query, do_wait, available);216default:217unreachable("Unsupported query type");218}219}220221VkResult222v3dv_get_query_pool_results_cpu(struct v3dv_device *device,223struct v3dv_query_pool *pool,224uint32_t first,225uint32_t count,226void *data,227VkDeviceSize stride,228VkQueryResultFlags flags)229{230assert(first < pool->query_count);231assert(first + count <= pool->query_count);232assert(data);233234const bool do_64bit = flags & VK_QUERY_RESULT_64_BIT;235const bool do_wait = flags & VK_QUERY_RESULT_WAIT_BIT;236const bool do_partial = flags & VK_QUERY_RESULT_PARTIAL_BIT;237238VkResult result = VK_SUCCESS;239for (uint32_t i = first; i < first + count; i++) {240bool available = false;241uint64_t value = get_query_result(device, pool, i, do_wait, &available);242243/**244* From the Vulkan 1.0 spec:245*246* "If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are247* both not set then no result values are written to pData for queries248* that are in the unavailable state at the time of the call, and249* vkGetQueryPoolResults returns VK_NOT_READY. However, availability250* state is still written to pData for those queries if251* VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set."252*/253uint32_t slot = 0;254255const bool write_result = available || do_partial;256if (write_result)257write_query_result(data, slot, do_64bit, value);258slot++;259260if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)261write_query_result(data, slot++, do_64bit, available ? 1u : 0u);262263if (!write_result)264result = VK_NOT_READY;265266data += stride;267}268269return result;270}271272VKAPI_ATTR VkResult VKAPI_CALL273v3dv_GetQueryPoolResults(VkDevice _device,274VkQueryPool queryPool,275uint32_t firstQuery,276uint32_t queryCount,277size_t dataSize,278void *pData,279VkDeviceSize stride,280VkQueryResultFlags flags)281{282V3DV_FROM_HANDLE(v3dv_device, device, _device);283V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);284285return v3dv_get_query_pool_results_cpu(device, pool, firstQuery, queryCount,286pData, stride, flags);287}288289VKAPI_ATTR void VKAPI_CALL290v3dv_CmdResetQueryPool(VkCommandBuffer commandBuffer,291VkQueryPool queryPool,292uint32_t firstQuery,293uint32_t queryCount)294{295V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);296V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);297298v3dv_cmd_buffer_reset_queries(cmd_buffer, pool, firstQuery, queryCount);299}300301VKAPI_ATTR void VKAPI_CALL302v3dv_CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer,303VkQueryPool queryPool,304uint32_t firstQuery,305uint32_t queryCount,306VkBuffer dstBuffer,307VkDeviceSize dstOffset,308VkDeviceSize stride,309VkQueryResultFlags flags)310{311V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);312V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);313V3DV_FROM_HANDLE(v3dv_buffer, dst, dstBuffer);314315v3dv_cmd_buffer_copy_query_results(cmd_buffer, pool,316firstQuery, queryCount,317dst, dstOffset, stride, flags);318}319320VKAPI_ATTR void VKAPI_CALL321v3dv_CmdBeginQuery(VkCommandBuffer commandBuffer,322VkQueryPool queryPool,323uint32_t query,324VkQueryControlFlags flags)325{326V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);327V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);328329v3dv_cmd_buffer_begin_query(cmd_buffer, pool, query, flags);330}331332VKAPI_ATTR void VKAPI_CALL333v3dv_CmdEndQuery(VkCommandBuffer commandBuffer,334VkQueryPool queryPool,335uint32_t query)336{337V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);338V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);339340v3dv_cmd_buffer_end_query(cmd_buffer, pool, query);341}342343344