1 /*
2 * Copyright 2019 Google LLC
3 * SPDX-License-Identifier: MIT
4 *
5 * based in part on anv and radv which are:
6 * Copyright © 2015 Intel Corporation
7 * Copyright © 2016 Red Hat.
8 * Copyright © 2016 Bas Nieuwenhuizen
9 */
10
11 #include "vn_query_pool.h"
12
13 #include "venus-protocol/vn_protocol_driver_query_pool.h"
14
15 #include "vn_device.h"
16
17 /* query pool commands */
18
19 VkResult
vn_CreateQueryPool(VkDevice device,const VkQueryPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkQueryPool * pQueryPool)20 vn_CreateQueryPool(VkDevice device,
21 const VkQueryPoolCreateInfo *pCreateInfo,
22 const VkAllocationCallbacks *pAllocator,
23 VkQueryPool *pQueryPool)
24 {
25 VN_TRACE_FUNC();
26 struct vn_device *dev = vn_device_from_handle(device);
27 const VkAllocationCallbacks *alloc =
28 pAllocator ? pAllocator : &dev->base.base.alloc;
29
30 struct vn_query_pool *pool =
31 vk_zalloc(alloc, sizeof(*pool), VN_DEFAULT_ALIGN,
32 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
33 if (!pool)
34 return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
35
36 vn_object_base_init(&pool->base, VK_OBJECT_TYPE_QUERY_POOL, &dev->base);
37
38 pool->allocator = *alloc;
39
40 switch (pCreateInfo->queryType) {
41 case VK_QUERY_TYPE_OCCLUSION:
42 pool->result_array_size = 1;
43 break;
44 case VK_QUERY_TYPE_PIPELINE_STATISTICS:
45 pool->result_array_size =
46 util_bitcount(pCreateInfo->pipelineStatistics);
47 break;
48 case VK_QUERY_TYPE_TIMESTAMP:
49 pool->result_array_size = 1;
50 break;
51 case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
52 pool->result_array_size = 2;
53 break;
54 default:
55 unreachable("bad query type");
56 break;
57 }
58
59 VkQueryPool pool_handle = vn_query_pool_to_handle(pool);
60 vn_async_vkCreateQueryPool(dev->instance, device, pCreateInfo, NULL,
61 &pool_handle);
62
63 *pQueryPool = pool_handle;
64
65 return VK_SUCCESS;
66 }
67
68 void
vn_DestroyQueryPool(VkDevice device,VkQueryPool queryPool,const VkAllocationCallbacks * pAllocator)69 vn_DestroyQueryPool(VkDevice device,
70 VkQueryPool queryPool,
71 const VkAllocationCallbacks *pAllocator)
72 {
73 VN_TRACE_FUNC();
74 struct vn_device *dev = vn_device_from_handle(device);
75 struct vn_query_pool *pool = vn_query_pool_from_handle(queryPool);
76 const VkAllocationCallbacks *alloc;
77
78 if (!pool)
79 return;
80
81 alloc = pAllocator ? pAllocator : &pool->allocator;
82
83 vn_async_vkDestroyQueryPool(dev->instance, device, queryPool, NULL);
84
85 vn_object_base_fini(&pool->base);
86 vk_free(alloc, pool);
87 }
88
89 void
vn_ResetQueryPool(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount)90 vn_ResetQueryPool(VkDevice device,
91 VkQueryPool queryPool,
92 uint32_t firstQuery,
93 uint32_t queryCount)
94 {
95 VN_TRACE_FUNC();
96 struct vn_device *dev = vn_device_from_handle(device);
97
98 vn_async_vkResetQueryPool(dev->instance, device, queryPool, firstQuery,
99 queryCount);
100 }
101
102 VkResult
vn_GetQueryPoolResults(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,size_t dataSize,void * pData,VkDeviceSize stride,VkQueryResultFlags flags)103 vn_GetQueryPoolResults(VkDevice device,
104 VkQueryPool queryPool,
105 uint32_t firstQuery,
106 uint32_t queryCount,
107 size_t dataSize,
108 void *pData,
109 VkDeviceSize stride,
110 VkQueryResultFlags flags)
111 {
112 VN_TRACE_FUNC();
113 struct vn_device *dev = vn_device_from_handle(device);
114 struct vn_query_pool *pool = vn_query_pool_from_handle(queryPool);
115 const VkAllocationCallbacks *alloc = &pool->allocator;
116
117 const size_t result_width = flags & VK_QUERY_RESULT_64_BIT ? 8 : 4;
118 const size_t result_size = pool->result_array_size * result_width;
119 const bool result_always_written =
120 flags & (VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_PARTIAL_BIT);
121
122 VkQueryResultFlags packed_flags = flags;
123 size_t packed_stride = result_size;
124 if (!result_always_written)
125 packed_flags |= VK_QUERY_RESULT_WITH_AVAILABILITY_BIT;
126 if (packed_flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
127 packed_stride += result_width;
128
129 const size_t packed_size = packed_stride * queryCount;
130 void *packed_data;
131 if (result_always_written && packed_stride == stride) {
132 packed_data = pData;
133 } else {
134 packed_data = vk_alloc(alloc, packed_size, VN_DEFAULT_ALIGN,
135 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
136 if (!packed_data)
137 return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
138 }
139
140 /* TODO the renderer should transparently vkCmdCopyQueryPoolResults to a
141 * coherent memory such that we can memcpy from the coherent memory to
142 * avoid this serialized round trip.
143 */
144 VkResult result = vn_call_vkGetQueryPoolResults(
145 dev->instance, device, queryPool, firstQuery, queryCount, packed_size,
146 packed_data, packed_stride, packed_flags);
147
148 if (packed_data == pData)
149 return vn_result(dev->instance, result);
150
151 const size_t copy_size =
152 result_size +
153 (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT ? result_width : 0);
154 const void *src = packed_data;
155 void *dst = pData;
156 if (result == VK_SUCCESS) {
157 for (uint32_t i = 0; i < queryCount; i++) {
158 memcpy(dst, src, copy_size);
159 src += packed_stride;
160 dst += stride;
161 }
162 } else if (result == VK_NOT_READY) {
163 assert(!result_always_written &&
164 (packed_flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT));
165 if (flags & VK_QUERY_RESULT_64_BIT) {
166 for (uint32_t i = 0; i < queryCount; i++) {
167 const bool avail = *(const uint64_t *)(src + result_size);
168 if (avail)
169 memcpy(dst, src, copy_size);
170 else if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
171 *(uint64_t *)(dst + result_size) = 0;
172
173 src += packed_stride;
174 dst += stride;
175 }
176 } else {
177 for (uint32_t i = 0; i < queryCount; i++) {
178 const bool avail = *(const uint32_t *)(src + result_size);
179 if (avail)
180 memcpy(dst, src, copy_size);
181 else if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
182 *(uint32_t *)(dst + result_size) = 0;
183
184 src += packed_stride;
185 dst += stride;
186 }
187 }
188 }
189
190 vk_free(alloc, packed_data);
191 return vn_result(dev->instance, result);
192 }
193