17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2020 Raspberry Pi 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "v3dv_private.h" 257ec681f3Smrg 267ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 277ec681f3Smrgv3dv_CreateQueryPool(VkDevice _device, 287ec681f3Smrg const VkQueryPoolCreateInfo *pCreateInfo, 297ec681f3Smrg const VkAllocationCallbacks *pAllocator, 307ec681f3Smrg VkQueryPool *pQueryPool) 317ec681f3Smrg{ 327ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 337ec681f3Smrg 347ec681f3Smrg assert(pCreateInfo->queryType == VK_QUERY_TYPE_OCCLUSION || 357ec681f3Smrg pCreateInfo->queryType == VK_QUERY_TYPE_TIMESTAMP); 367ec681f3Smrg assert(pCreateInfo->queryCount > 0); 377ec681f3Smrg 387ec681f3Smrg struct v3dv_query_pool *pool = 397ec681f3Smrg vk_object_zalloc(&device->vk, pAllocator, sizeof(*pool), 407ec681f3Smrg VK_OBJECT_TYPE_QUERY_POOL); 417ec681f3Smrg if (pool == NULL) 427ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 437ec681f3Smrg 447ec681f3Smrg pool->query_type = pCreateInfo->queryType; 457ec681f3Smrg pool->query_count = pCreateInfo->queryCount; 467ec681f3Smrg 477ec681f3Smrg VkResult result; 487ec681f3Smrg 497ec681f3Smrg const uint32_t pool_bytes = sizeof(struct v3dv_query) * pool->query_count; 507ec681f3Smrg pool->queries = vk_alloc2(&device->vk.alloc, pAllocator, pool_bytes, 8, 517ec681f3Smrg VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 527ec681f3Smrg if (pool->queries == NULL) { 537ec681f3Smrg result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 547ec681f3Smrg goto fail; 557ec681f3Smrg } 567ec681f3Smrg 577ec681f3Smrg if (pool->query_type == VK_QUERY_TYPE_OCCLUSION) { 587ec681f3Smrg /* The hardware allows us to setup groups of 16 queries in consecutive 597ec681f3Smrg * 4-byte addresses, requiring only that each group of 16 queries is 607ec681f3Smrg * aligned to a 1024 byte boundary. 617ec681f3Smrg */ 627ec681f3Smrg const uint32_t query_groups = DIV_ROUND_UP(pool->query_count, 16); 637ec681f3Smrg const uint32_t bo_size = query_groups * 1024; 647ec681f3Smrg pool->bo = v3dv_bo_alloc(device, bo_size, "query", true); 657ec681f3Smrg if (!pool->bo) { 667ec681f3Smrg result = vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); 677ec681f3Smrg goto fail; 687ec681f3Smrg } 697ec681f3Smrg if (!v3dv_bo_map(device, pool->bo, bo_size)) { 707ec681f3Smrg result = vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); 717ec681f3Smrg goto fail; 727ec681f3Smrg } 737ec681f3Smrg } 747ec681f3Smrg 757ec681f3Smrg uint32_t i; 767ec681f3Smrg for (i = 0; i < pool->query_count; i++) { 777ec681f3Smrg pool->queries[i].maybe_available = false; 787ec681f3Smrg switch (pool->query_type) { 797ec681f3Smrg case VK_QUERY_TYPE_OCCLUSION: { 807ec681f3Smrg const uint32_t query_group = i / 16; 817ec681f3Smrg const uint32_t query_offset = query_group * 1024 + (i % 16) * 4; 827ec681f3Smrg pool->queries[i].bo = pool->bo; 837ec681f3Smrg pool->queries[i].offset = query_offset; 847ec681f3Smrg break; 857ec681f3Smrg } 867ec681f3Smrg case VK_QUERY_TYPE_TIMESTAMP: 877ec681f3Smrg pool->queries[i].value = 0; 887ec681f3Smrg break; 897ec681f3Smrg default: 907ec681f3Smrg unreachable("Unsupported query type"); 917ec681f3Smrg } 927ec681f3Smrg } 937ec681f3Smrg 947ec681f3Smrg *pQueryPool = v3dv_query_pool_to_handle(pool); 957ec681f3Smrg 967ec681f3Smrg return VK_SUCCESS; 977ec681f3Smrg 987ec681f3Smrgfail: 997ec681f3Smrg if (pool->bo) 1007ec681f3Smrg v3dv_bo_free(device, pool->bo); 1017ec681f3Smrg if (pool->queries) 1027ec681f3Smrg vk_free2(&device->vk.alloc, pAllocator, pool->queries); 1037ec681f3Smrg vk_object_free(&device->vk, pAllocator, pool); 1047ec681f3Smrg 1057ec681f3Smrg return result; 1067ec681f3Smrg} 1077ec681f3Smrg 1087ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 1097ec681f3Smrgv3dv_DestroyQueryPool(VkDevice _device, 1107ec681f3Smrg VkQueryPool queryPool, 1117ec681f3Smrg const VkAllocationCallbacks *pAllocator) 1127ec681f3Smrg{ 1137ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 1147ec681f3Smrg V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool); 1157ec681f3Smrg 1167ec681f3Smrg if (!pool) 1177ec681f3Smrg return; 1187ec681f3Smrg 1197ec681f3Smrg if (pool->bo) 1207ec681f3Smrg v3dv_bo_free(device, pool->bo); 1217ec681f3Smrg 1227ec681f3Smrg if (pool->queries) 1237ec681f3Smrg vk_free2(&device->vk.alloc, pAllocator, pool->queries); 1247ec681f3Smrg 1257ec681f3Smrg vk_object_free(&device->vk, pAllocator, pool); 1267ec681f3Smrg} 1277ec681f3Smrg 1287ec681f3Smrgstatic void 1297ec681f3Smrgwrite_query_result(void *dst, uint32_t idx, bool do_64bit, uint64_t value) 1307ec681f3Smrg{ 1317ec681f3Smrg if (do_64bit) { 1327ec681f3Smrg uint64_t *dst64 = (uint64_t *) dst; 1337ec681f3Smrg dst64[idx] = value; 1347ec681f3Smrg } else { 1357ec681f3Smrg uint32_t *dst32 = (uint32_t *) dst; 1367ec681f3Smrg dst32[idx] = (uint32_t) value; 1377ec681f3Smrg } 1387ec681f3Smrg} 1397ec681f3Smrg 1407ec681f3Smrgstatic VkResult 1417ec681f3Smrgget_occlusion_query_result(struct v3dv_device *device, 1427ec681f3Smrg struct v3dv_query_pool *pool, 1437ec681f3Smrg uint32_t query, 1447ec681f3Smrg bool do_wait, 1457ec681f3Smrg bool *available, 1467ec681f3Smrg uint64_t *value) 1477ec681f3Smrg{ 1487ec681f3Smrg assert(pool && pool->query_type == VK_QUERY_TYPE_OCCLUSION); 1497ec681f3Smrg 1507ec681f3Smrg struct v3dv_query *q = &pool->queries[query]; 1517ec681f3Smrg assert(q->bo && q->bo->map); 1527ec681f3Smrg 1537ec681f3Smrg if (do_wait) { 1547ec681f3Smrg /* From the Vulkan 1.0 spec: 1557ec681f3Smrg * 1567ec681f3Smrg * "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not 1577ec681f3Smrg * become available in a finite amount of time (e.g. due to not 1587ec681f3Smrg * issuing a query since the last reset), a VK_ERROR_DEVICE_LOST 1597ec681f3Smrg * error may occur." 1607ec681f3Smrg */ 1617ec681f3Smrg if (!q->maybe_available) 1627ec681f3Smrg return vk_error(device, VK_ERROR_DEVICE_LOST); 1637ec681f3Smrg 1647ec681f3Smrg if (!v3dv_bo_wait(device, q->bo, 0xffffffffffffffffull)) 1657ec681f3Smrg return vk_error(device, VK_ERROR_DEVICE_LOST); 1667ec681f3Smrg 1677ec681f3Smrg *available = true; 1687ec681f3Smrg } else { 1697ec681f3Smrg *available = q->maybe_available && v3dv_bo_wait(device, q->bo, 0); 1707ec681f3Smrg } 1717ec681f3Smrg 1727ec681f3Smrg const uint8_t *query_addr = ((uint8_t *) q->bo->map) + q->offset; 1737ec681f3Smrg *value = (uint64_t) *((uint32_t *)query_addr); 1747ec681f3Smrg return VK_SUCCESS; 1757ec681f3Smrg} 1767ec681f3Smrg 1777ec681f3Smrgstatic VkResult 1787ec681f3Smrgget_timestamp_query_result(struct v3dv_device *device, 1797ec681f3Smrg struct v3dv_query_pool *pool, 1807ec681f3Smrg uint32_t query, 1817ec681f3Smrg bool do_wait, 1827ec681f3Smrg bool *available, 1837ec681f3Smrg uint64_t *value) 1847ec681f3Smrg{ 1857ec681f3Smrg assert(pool && pool->query_type == VK_QUERY_TYPE_TIMESTAMP); 1867ec681f3Smrg 1877ec681f3Smrg struct v3dv_query *q = &pool->queries[query]; 1887ec681f3Smrg 1897ec681f3Smrg if (do_wait) { 1907ec681f3Smrg /* From the Vulkan 1.0 spec: 1917ec681f3Smrg * 1927ec681f3Smrg * "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not 1937ec681f3Smrg * become available in a finite amount of time (e.g. due to not 1947ec681f3Smrg * issuing a query since the last reset), a VK_ERROR_DEVICE_LOST 1957ec681f3Smrg * error may occur." 1967ec681f3Smrg */ 1977ec681f3Smrg if (!q->maybe_available) 1987ec681f3Smrg return vk_error(device, VK_ERROR_DEVICE_LOST); 1997ec681f3Smrg 2007ec681f3Smrg *available = true; 2017ec681f3Smrg } else { 2027ec681f3Smrg *available = q->maybe_available; 2037ec681f3Smrg } 2047ec681f3Smrg 2057ec681f3Smrg *value = q->value; 2067ec681f3Smrg return VK_SUCCESS; 2077ec681f3Smrg} 2087ec681f3Smrg 2097ec681f3Smrgstatic VkResult 2107ec681f3Smrgget_query_result(struct v3dv_device *device, 2117ec681f3Smrg struct v3dv_query_pool *pool, 2127ec681f3Smrg uint32_t query, 2137ec681f3Smrg bool do_wait, 2147ec681f3Smrg bool *available, 2157ec681f3Smrg uint64_t *value) 2167ec681f3Smrg{ 2177ec681f3Smrg switch (pool->query_type) { 2187ec681f3Smrg case VK_QUERY_TYPE_OCCLUSION: 2197ec681f3Smrg return get_occlusion_query_result(device, pool, query, do_wait, 2207ec681f3Smrg available, value); 2217ec681f3Smrg case VK_QUERY_TYPE_TIMESTAMP: 2227ec681f3Smrg return get_timestamp_query_result(device, pool, query, do_wait, 2237ec681f3Smrg available, value); 2247ec681f3Smrg default: 2257ec681f3Smrg unreachable("Unsupported query type"); 2267ec681f3Smrg } 2277ec681f3Smrg} 2287ec681f3Smrg 2297ec681f3SmrgVkResult 2307ec681f3Smrgv3dv_get_query_pool_results_cpu(struct v3dv_device *device, 2317ec681f3Smrg struct v3dv_query_pool *pool, 2327ec681f3Smrg uint32_t first, 2337ec681f3Smrg uint32_t count, 2347ec681f3Smrg void *data, 2357ec681f3Smrg VkDeviceSize stride, 2367ec681f3Smrg VkQueryResultFlags flags) 2377ec681f3Smrg{ 2387ec681f3Smrg assert(first < pool->query_count); 2397ec681f3Smrg assert(first + count <= pool->query_count); 2407ec681f3Smrg assert(data); 2417ec681f3Smrg 2427ec681f3Smrg const bool do_64bit = flags & VK_QUERY_RESULT_64_BIT; 2437ec681f3Smrg const bool do_wait = flags & VK_QUERY_RESULT_WAIT_BIT; 2447ec681f3Smrg const bool do_partial = flags & VK_QUERY_RESULT_PARTIAL_BIT; 2457ec681f3Smrg 2467ec681f3Smrg VkResult result = VK_SUCCESS; 2477ec681f3Smrg for (uint32_t i = first; i < first + count; i++) { 2487ec681f3Smrg bool available = false; 2497ec681f3Smrg uint64_t value = 0; 2507ec681f3Smrg VkResult query_result = 2517ec681f3Smrg get_query_result(device, pool, i, do_wait, &available, &value); 2527ec681f3Smrg if (query_result == VK_ERROR_DEVICE_LOST) 2537ec681f3Smrg result = VK_ERROR_DEVICE_LOST; 2547ec681f3Smrg 2557ec681f3Smrg /** 2567ec681f3Smrg * From the Vulkan 1.0 spec: 2577ec681f3Smrg * 2587ec681f3Smrg * "If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are 2597ec681f3Smrg * both not set then no result values are written to pData for queries 2607ec681f3Smrg * that are in the unavailable state at the time of the call, and 2617ec681f3Smrg * vkGetQueryPoolResults returns VK_NOT_READY. However, availability 2627ec681f3Smrg * state is still written to pData for those queries if 2637ec681f3Smrg * VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set." 2647ec681f3Smrg */ 2657ec681f3Smrg uint32_t slot = 0; 2667ec681f3Smrg 2677ec681f3Smrg const bool write_result = available || do_partial; 2687ec681f3Smrg if (write_result) 2697ec681f3Smrg write_query_result(data, slot, do_64bit, value); 2707ec681f3Smrg slot++; 2717ec681f3Smrg 2727ec681f3Smrg if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) 2737ec681f3Smrg write_query_result(data, slot++, do_64bit, available ? 1u : 0u); 2747ec681f3Smrg 2757ec681f3Smrg if (!write_result && result != VK_ERROR_DEVICE_LOST) 2767ec681f3Smrg result = VK_NOT_READY; 2777ec681f3Smrg 2787ec681f3Smrg data += stride; 2797ec681f3Smrg } 2807ec681f3Smrg 2817ec681f3Smrg return result; 2827ec681f3Smrg} 2837ec681f3Smrg 2847ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 2857ec681f3Smrgv3dv_GetQueryPoolResults(VkDevice _device, 2867ec681f3Smrg VkQueryPool queryPool, 2877ec681f3Smrg uint32_t firstQuery, 2887ec681f3Smrg uint32_t queryCount, 2897ec681f3Smrg size_t dataSize, 2907ec681f3Smrg void *pData, 2917ec681f3Smrg VkDeviceSize stride, 2927ec681f3Smrg VkQueryResultFlags flags) 2937ec681f3Smrg{ 2947ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 2957ec681f3Smrg V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool); 2967ec681f3Smrg 2977ec681f3Smrg return v3dv_get_query_pool_results_cpu(device, pool, firstQuery, queryCount, 2987ec681f3Smrg pData, stride, flags); 2997ec681f3Smrg} 3007ec681f3Smrg 3017ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 3027ec681f3Smrgv3dv_CmdResetQueryPool(VkCommandBuffer commandBuffer, 3037ec681f3Smrg VkQueryPool queryPool, 3047ec681f3Smrg uint32_t firstQuery, 3057ec681f3Smrg uint32_t queryCount) 3067ec681f3Smrg{ 3077ec681f3Smrg V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer); 3087ec681f3Smrg V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool); 3097ec681f3Smrg 3107ec681f3Smrg v3dv_cmd_buffer_reset_queries(cmd_buffer, pool, firstQuery, queryCount); 3117ec681f3Smrg} 3127ec681f3Smrg 3137ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 3147ec681f3Smrgv3dv_CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, 3157ec681f3Smrg VkQueryPool queryPool, 3167ec681f3Smrg uint32_t firstQuery, 3177ec681f3Smrg uint32_t queryCount, 3187ec681f3Smrg VkBuffer dstBuffer, 3197ec681f3Smrg VkDeviceSize dstOffset, 3207ec681f3Smrg VkDeviceSize stride, 3217ec681f3Smrg VkQueryResultFlags flags) 3227ec681f3Smrg{ 3237ec681f3Smrg V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer); 3247ec681f3Smrg V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool); 3257ec681f3Smrg V3DV_FROM_HANDLE(v3dv_buffer, dst, dstBuffer); 3267ec681f3Smrg 3277ec681f3Smrg v3dv_cmd_buffer_copy_query_results(cmd_buffer, pool, 3287ec681f3Smrg firstQuery, queryCount, 3297ec681f3Smrg dst, dstOffset, stride, flags); 3307ec681f3Smrg} 3317ec681f3Smrg 3327ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 3337ec681f3Smrgv3dv_CmdBeginQuery(VkCommandBuffer commandBuffer, 3347ec681f3Smrg VkQueryPool queryPool, 3357ec681f3Smrg uint32_t query, 3367ec681f3Smrg VkQueryControlFlags flags) 3377ec681f3Smrg{ 3387ec681f3Smrg V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer); 3397ec681f3Smrg V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool); 3407ec681f3Smrg 3417ec681f3Smrg v3dv_cmd_buffer_begin_query(cmd_buffer, pool, query, flags); 3427ec681f3Smrg} 3437ec681f3Smrg 3447ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 3457ec681f3Smrgv3dv_CmdEndQuery(VkCommandBuffer commandBuffer, 3467ec681f3Smrg VkQueryPool queryPool, 3477ec681f3Smrg uint32_t query) 3487ec681f3Smrg{ 3497ec681f3Smrg V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer); 3507ec681f3Smrg V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool); 3517ec681f3Smrg 3527ec681f3Smrg v3dv_cmd_buffer_end_query(cmd_buffer, pool, query); 3537ec681f3Smrg} 354