Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/broadcom/vulkan/v3dv_query.c
4560 views
1
/*
2
* Copyright © 2020 Raspberry Pi
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
*/
23
24
#include "v3dv_private.h"
25
26
VKAPI_ATTR VkResult VKAPI_CALL
27
v3dv_CreateQueryPool(VkDevice _device,
28
const VkQueryPoolCreateInfo *pCreateInfo,
29
const VkAllocationCallbacks *pAllocator,
30
VkQueryPool *pQueryPool)
31
{
32
V3DV_FROM_HANDLE(v3dv_device, device, _device);
33
34
assert(pCreateInfo->queryType == VK_QUERY_TYPE_OCCLUSION ||
35
pCreateInfo->queryType == VK_QUERY_TYPE_TIMESTAMP);
36
assert(pCreateInfo->queryCount > 0);
37
38
struct v3dv_query_pool *pool =
39
vk_object_zalloc(&device->vk, pAllocator, sizeof(*pool),
40
VK_OBJECT_TYPE_QUERY_POOL);
41
if (pool == NULL)
42
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
43
44
pool->query_type = pCreateInfo->queryType;
45
pool->query_count = pCreateInfo->queryCount;
46
47
VkResult result;
48
49
const uint32_t pool_bytes = sizeof(struct v3dv_query) * pool->query_count;
50
pool->queries = vk_alloc2(&device->vk.alloc, pAllocator, pool_bytes, 8,
51
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
52
if (pool->queries == NULL) {
53
result = vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
54
goto fail;
55
}
56
57
if (pool->query_type == VK_QUERY_TYPE_OCCLUSION) {
58
/* The hardware allows us to setup groups of 16 queries in consecutive
59
* 4-byte addresses, requiring only that each group of 16 queries is
60
* aligned to a 1024 byte boundary.
61
*/
62
const uint32_t query_groups = DIV_ROUND_UP(pool->query_count, 16);
63
const uint32_t bo_size = query_groups * 1024;
64
pool->bo = v3dv_bo_alloc(device, bo_size, "query", true);
65
if (!pool->bo) {
66
result = vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
67
goto fail;
68
}
69
if (!v3dv_bo_map(device, pool->bo, bo_size)) {
70
result = vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
71
goto fail;
72
}
73
}
74
75
uint32_t i;
76
for (i = 0; i < pool->query_count; i++) {
77
pool->queries[i].maybe_available = false;
78
switch (pool->query_type) {
79
case VK_QUERY_TYPE_OCCLUSION: {
80
const uint32_t query_group = i / 16;
81
const uint32_t query_offset = query_group * 1024 + (i % 16) * 4;
82
pool->queries[i].bo = pool->bo;
83
pool->queries[i].offset = query_offset;
84
break;
85
}
86
case VK_QUERY_TYPE_TIMESTAMP:
87
pool->queries[i].value = 0;
88
break;
89
default:
90
unreachable("Unsupported query type");
91
}
92
}
93
94
*pQueryPool = v3dv_query_pool_to_handle(pool);
95
96
return VK_SUCCESS;
97
98
fail:
99
if (pool->bo)
100
v3dv_bo_free(device, pool->bo);
101
if (pool->queries)
102
vk_free2(&device->vk.alloc, pAllocator, pool->queries);
103
vk_object_free(&device->vk, pAllocator, pool);
104
105
return result;
106
}
107
108
VKAPI_ATTR void VKAPI_CALL
109
v3dv_DestroyQueryPool(VkDevice _device,
110
VkQueryPool queryPool,
111
const VkAllocationCallbacks *pAllocator)
112
{
113
V3DV_FROM_HANDLE(v3dv_device, device, _device);
114
V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);
115
116
if (!pool)
117
return;
118
119
if (pool->bo)
120
v3dv_bo_free(device, pool->bo);
121
122
if (pool->queries)
123
vk_free2(&device->vk.alloc, pAllocator, pool->queries);
124
125
vk_object_free(&device->vk, pAllocator, pool);
126
}
127
128
static void
129
write_query_result(void *dst, uint32_t idx, bool do_64bit, uint64_t value)
130
{
131
if (do_64bit) {
132
uint64_t *dst64 = (uint64_t *) dst;
133
dst64[idx] = value;
134
} else {
135
uint32_t *dst32 = (uint32_t *) dst;
136
dst32[idx] = (uint32_t) value;
137
}
138
}
139
140
static uint64_t
141
get_occlusion_query_result(struct v3dv_device *device,
142
struct v3dv_query_pool *pool,
143
uint32_t query,
144
bool do_wait,
145
bool *available)
146
{
147
assert(pool && pool->query_type == VK_QUERY_TYPE_OCCLUSION);
148
149
struct v3dv_query *q = &pool->queries[query];
150
assert(q->bo && q->bo->map);
151
152
if (do_wait) {
153
/* From the Vulkan 1.0 spec:
154
*
155
* "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not
156
* become available in a finite amount of time (e.g. due to not
157
* issuing a query since the last reset), a VK_ERROR_DEVICE_LOST
158
* error may occur."
159
*/
160
if (!q->maybe_available)
161
return vk_error(device->instance, VK_ERROR_DEVICE_LOST);
162
163
if (!v3dv_bo_wait(device, q->bo, 0xffffffffffffffffull))
164
return vk_error(device->instance, VK_ERROR_DEVICE_LOST);
165
166
*available = true;
167
} else {
168
*available = q->maybe_available && v3dv_bo_wait(device, q->bo, 0);
169
}
170
171
const uint8_t *query_addr = ((uint8_t *) q->bo->map) + q->offset;
172
return (uint64_t) *((uint32_t *)query_addr);
173
}
174
175
static uint64_t
176
get_timestamp_query_result(struct v3dv_device *device,
177
struct v3dv_query_pool *pool,
178
uint32_t query,
179
bool do_wait,
180
bool *available)
181
{
182
assert(pool && pool->query_type == VK_QUERY_TYPE_TIMESTAMP);
183
184
struct v3dv_query *q = &pool->queries[query];
185
186
if (do_wait) {
187
/* From the Vulkan 1.0 spec:
188
*
189
* "If VK_QUERY_RESULT_WAIT_BIT is set, (...) If the query does not
190
* become available in a finite amount of time (e.g. due to not
191
* issuing a query since the last reset), a VK_ERROR_DEVICE_LOST
192
* error may occur."
193
*/
194
if (!q->maybe_available)
195
return vk_error(device->instance, VK_ERROR_DEVICE_LOST);
196
197
*available = true;
198
} else {
199
*available = q->maybe_available;
200
}
201
202
return q->value;
203
}
204
205
static uint64_t
206
get_query_result(struct v3dv_device *device,
207
struct v3dv_query_pool *pool,
208
uint32_t query,
209
bool do_wait,
210
bool *available)
211
{
212
switch (pool->query_type) {
213
case VK_QUERY_TYPE_OCCLUSION:
214
return get_occlusion_query_result(device, pool, query, do_wait, available);
215
case VK_QUERY_TYPE_TIMESTAMP:
216
return get_timestamp_query_result(device, pool, query, do_wait, available);
217
default:
218
unreachable("Unsupported query type");
219
}
220
}
221
222
VkResult
223
v3dv_get_query_pool_results_cpu(struct v3dv_device *device,
224
struct v3dv_query_pool *pool,
225
uint32_t first,
226
uint32_t count,
227
void *data,
228
VkDeviceSize stride,
229
VkQueryResultFlags flags)
230
{
231
assert(first < pool->query_count);
232
assert(first + count <= pool->query_count);
233
assert(data);
234
235
const bool do_64bit = flags & VK_QUERY_RESULT_64_BIT;
236
const bool do_wait = flags & VK_QUERY_RESULT_WAIT_BIT;
237
const bool do_partial = flags & VK_QUERY_RESULT_PARTIAL_BIT;
238
239
VkResult result = VK_SUCCESS;
240
for (uint32_t i = first; i < first + count; i++) {
241
bool available = false;
242
uint64_t value = get_query_result(device, pool, i, do_wait, &available);
243
244
/**
245
* From the Vulkan 1.0 spec:
246
*
247
* "If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are
248
* both not set then no result values are written to pData for queries
249
* that are in the unavailable state at the time of the call, and
250
* vkGetQueryPoolResults returns VK_NOT_READY. However, availability
251
* state is still written to pData for those queries if
252
* VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set."
253
*/
254
uint32_t slot = 0;
255
256
const bool write_result = available || do_partial;
257
if (write_result)
258
write_query_result(data, slot, do_64bit, value);
259
slot++;
260
261
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
262
write_query_result(data, slot++, do_64bit, available ? 1u : 0u);
263
264
if (!write_result)
265
result = VK_NOT_READY;
266
267
data += stride;
268
}
269
270
return result;
271
}
272
273
VKAPI_ATTR VkResult VKAPI_CALL
274
v3dv_GetQueryPoolResults(VkDevice _device,
275
VkQueryPool queryPool,
276
uint32_t firstQuery,
277
uint32_t queryCount,
278
size_t dataSize,
279
void *pData,
280
VkDeviceSize stride,
281
VkQueryResultFlags flags)
282
{
283
V3DV_FROM_HANDLE(v3dv_device, device, _device);
284
V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);
285
286
return v3dv_get_query_pool_results_cpu(device, pool, firstQuery, queryCount,
287
pData, stride, flags);
288
}
289
290
VKAPI_ATTR void VKAPI_CALL
291
v3dv_CmdResetQueryPool(VkCommandBuffer commandBuffer,
292
VkQueryPool queryPool,
293
uint32_t firstQuery,
294
uint32_t queryCount)
295
{
296
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
297
V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);
298
299
v3dv_cmd_buffer_reset_queries(cmd_buffer, pool, firstQuery, queryCount);
300
}
301
302
VKAPI_ATTR void VKAPI_CALL
303
v3dv_CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer,
304
VkQueryPool queryPool,
305
uint32_t firstQuery,
306
uint32_t queryCount,
307
VkBuffer dstBuffer,
308
VkDeviceSize dstOffset,
309
VkDeviceSize stride,
310
VkQueryResultFlags flags)
311
{
312
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
313
V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);
314
V3DV_FROM_HANDLE(v3dv_buffer, dst, dstBuffer);
315
316
v3dv_cmd_buffer_copy_query_results(cmd_buffer, pool,
317
firstQuery, queryCount,
318
dst, dstOffset, stride, flags);
319
}
320
321
VKAPI_ATTR void VKAPI_CALL
322
v3dv_CmdBeginQuery(VkCommandBuffer commandBuffer,
323
VkQueryPool queryPool,
324
uint32_t query,
325
VkQueryControlFlags flags)
326
{
327
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
328
V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);
329
330
v3dv_cmd_buffer_begin_query(cmd_buffer, pool, query, flags);
331
}
332
333
VKAPI_ATTR void VKAPI_CALL
334
v3dv_CmdEndQuery(VkCommandBuffer commandBuffer,
335
VkQueryPool queryPool,
336
uint32_t query)
337
{
338
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
339
V3DV_FROM_HANDLE(v3dv_query_pool, pool, queryPool);
340
341
v3dv_cmd_buffer_end_query(cmd_buffer, pool, query);
342
}
343
344