1 #include "zink_query.h"
3 #include "zink_context.h"
4 #include "zink_fence.h"
5 #include "zink_resource.h"
6 #include "zink_screen.h"
8 #include "util/hash_table.h"
10 #include "util/u_dump.h"
11 #include "util/u_inlines.h"
12 #include "util/u_memory.h"
14 #define NUM_QUERIES 50
17 enum pipe_query_type type
;
19 VkQueryPool query_pool
;
20 unsigned last_checked_query
, curr_query
, num_queries
;
28 bool active
; /* query is considered active by vk */
29 bool needs_reset
; /* query is considered active by vk and cannot be destroyed */
30 bool dead
; /* query should be destroyed when its fence finishes */
33 struct list_head active_list
;
35 union pipe_query_result accumulated_result
;
39 convert_query_type(unsigned query_type
, bool *use_64bit
, bool *precise
)
44 case PIPE_QUERY_OCCLUSION_COUNTER
:
48 case PIPE_QUERY_OCCLUSION_PREDICATE
:
49 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE
:
50 return VK_QUERY_TYPE_OCCLUSION
;
51 case PIPE_QUERY_TIMESTAMP
:
53 return VK_QUERY_TYPE_TIMESTAMP
;
54 case PIPE_QUERY_PIPELINE_STATISTICS
:
55 case PIPE_QUERY_PRIMITIVES_GENERATED
:
56 return VK_QUERY_TYPE_PIPELINE_STATISTICS
;
57 case PIPE_QUERY_PRIMITIVES_EMITTED
:
59 return VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
;
61 debug_printf("unknown query: %s\n",
62 util_str_query_type(query_type
, true));
63 unreachable("zink: unknown query type");
67 static struct pipe_query
*
68 zink_create_query(struct pipe_context
*pctx
,
69 unsigned query_type
, unsigned index
)
71 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
72 struct zink_query
*query
= CALLOC_STRUCT(zink_query
);
73 VkQueryPoolCreateInfo pool_create
= {};
79 query
->type
= query_type
;
80 query
->vkqtype
= convert_query_type(query_type
, &query
->use_64bit
, &query
->precise
);
81 if (query
->vkqtype
== -1)
84 query
->num_queries
= query_type
== PIPE_QUERY_TIMESTAMP
? 1 : NUM_QUERIES
;
85 query
->curr_query
= 0;
87 pool_create
.sType
= VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
;
88 pool_create
.queryType
= query
->vkqtype
;
89 pool_create
.queryCount
= query
->num_queries
;
90 if (query_type
== PIPE_QUERY_PRIMITIVES_GENERATED
)
91 pool_create
.pipelineStatistics
= VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
;
93 VkResult status
= vkCreateQueryPool(screen
->dev
, &pool_create
, NULL
, &query
->query_pool
);
94 if (status
!= VK_SUCCESS
) {
98 struct zink_batch
*batch
= zink_batch_no_rp(zink_context(pctx
));
99 vkCmdResetQueryPool(batch
->cmdbuf
, query
->query_pool
, 0, query
->num_queries
);
100 return (struct pipe_query
*)query
;
104 wait_query(struct pipe_context
*pctx
, struct zink_query
*query
)
106 struct pipe_fence_handle
*fence
= NULL
;
108 pctx
->flush(pctx
, &fence
, PIPE_FLUSH_HINT_FINISH
);
110 pctx
->screen
->fence_finish(pctx
->screen
, NULL
, fence
,
111 PIPE_TIMEOUT_INFINITE
);
112 pctx
->screen
->fence_reference(pctx
->screen
, &fence
, NULL
);
117 destroy_query(struct zink_screen
*screen
, struct zink_query
*query
)
119 assert(!p_atomic_read(&query
->fences
));
120 vkDestroyQueryPool(screen
->dev
, query
->query_pool
, NULL
);
125 zink_destroy_query(struct pipe_context
*pctx
,
126 struct pipe_query
*q
)
128 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
129 struct zink_query
*query
= (struct zink_query
*)q
;
131 p_atomic_set(&query
->dead
, true);
132 if (p_atomic_read(&query
->fences
)) {
133 if (query
->xfb_running
)
134 wait_query(pctx
, query
);
138 destroy_query(screen
, query
);
142 zink_prune_queries(struct zink_screen
*screen
, struct zink_fence
*fence
)
144 set_foreach(fence
->active_queries
, entry
) {
145 struct zink_query
*query
= (void*)entry
->key
;
146 if (!p_atomic_dec_return(&query
->fences
)) {
147 if (p_atomic_read(&query
->dead
))
148 destroy_query(screen
, query
);
151 _mesa_set_destroy(fence
->active_queries
, NULL
);
152 fence
->active_queries
= NULL
;
156 get_query_result(struct pipe_context
*pctx
,
157 struct pipe_query
*q
,
159 union pipe_query_result
*result
)
161 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
162 struct zink_query
*query
= (struct zink_query
*)q
;
163 VkQueryResultFlagBits flags
= 0;
166 flags
|= VK_QUERY_RESULT_WAIT_BIT
;
168 if (query
->use_64bit
)
169 flags
|= VK_QUERY_RESULT_64_BIT
;
171 if (result
!= &query
->accumulated_result
) {
172 memcpy(result
, &query
->accumulated_result
, sizeof(query
->accumulated_result
));
173 util_query_clear_result(&query
->accumulated_result
, query
->type
);
175 assert(query
->vkqtype
!= VK_QUERY_TYPE_TIMESTAMP
);
176 flags
|= VK_QUERY_RESULT_PARTIAL_BIT
;
179 // union pipe_query_result results[NUM_QUERIES * 2];
180 /* xfb queries return 2 results */
181 uint64_t results
[NUM_QUERIES
* 2];
182 memset(results
, 0, sizeof(results
));
183 int num_results
= query
->curr_query
- query
->last_checked_query
;
184 if (query
->vkqtype
== VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
) {
185 /* this query emits 2 values */
186 assert(query
->curr_query
<= ARRAY_SIZE(results
) / 2);
187 VkResult status
= vkGetQueryPoolResults(screen
->dev
, query
->query_pool
,
188 query
->last_checked_query
, num_results
,
193 if (status
!= VK_SUCCESS
)
195 /* multiply for correct looping behavior below */
198 assert(query
->curr_query
<= ARRAY_SIZE(results
));
199 VkResult status
= vkGetQueryPoolResults(screen
->dev
, query
->query_pool
,
200 query
->last_checked_query
, num_results
,
205 if (status
!= VK_SUCCESS
)
209 for (int i
= 0; i
< num_results
; ++i
) {
210 switch (query
->type
) {
211 case PIPE_QUERY_OCCLUSION_PREDICATE
:
212 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE
:
213 case PIPE_QUERY_SO_OVERFLOW_PREDICATE
:
214 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE
:
215 case PIPE_QUERY_GPU_FINISHED
:
216 result
->b
|= results
[i
] != 0;
219 case PIPE_QUERY_OCCLUSION_COUNTER
:
220 result
->u64
+= results
[i
];
222 case PIPE_QUERY_PRIMITIVES_GENERATED
:
223 result
->u32
+= results
[i
];
225 case PIPE_QUERY_PRIMITIVES_EMITTED
:
226 /* A query pool created with this type will capture 2 integers -
227 * numPrimitivesWritten and numPrimitivesNeeded -
228 * for the specified vertex stream output from the last vertex processing stage.
229 * - from VK_EXT_transform_feedback spec
231 result
->u64
+= results
[i
];
236 debug_printf("unhangled query type: %s\n",
237 util_str_query_type(query
->type
, true));
238 unreachable("unexpected query type");
241 query
->last_checked_query
= query
->curr_query
;
247 reset_pool(struct zink_context
*ctx
, struct zink_batch
*batch
, struct zink_query
*q
)
249 /* This command must only be called outside of a render pass instance
251 * - vkCmdResetQueryPool spec
253 batch
= zink_batch_no_rp(ctx
);
255 get_query_result(&ctx
->base
, (struct pipe_query
*)q
, false, &q
->accumulated_result
);
256 vkCmdResetQueryPool(batch
->cmdbuf
, q
->query_pool
, 0, q
->num_queries
);
257 q
->last_checked_query
= q
->curr_query
= 0;
258 q
->needs_reset
= false;
262 begin_query(struct zink_context
*ctx
, struct zink_batch
*batch
, struct zink_query
*q
)
264 VkQueryControlFlags flags
= 0;
267 reset_pool(ctx
, batch
, q
);
268 assert(q
->curr_query
< q
->num_queries
);
270 flags
|= VK_QUERY_CONTROL_PRECISE_BIT
;
271 if (q
->vkqtype
== VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
) {
272 zink_screen(ctx
->base
.screen
)->vk_CmdBeginQueryIndexedEXT(batch
->cmdbuf
,
277 q
->xfb_running
= true;
279 vkCmdBeginQuery(batch
->cmdbuf
, q
->query_pool
, q
->curr_query
, flags
);
281 if (!batch
->active_queries
)
282 batch
->active_queries
= _mesa_set_create(NULL
, _mesa_hash_pointer
, _mesa_key_pointer_equal
);
283 assert(batch
->active_queries
);
284 p_atomic_inc(&q
->fences
);
285 _mesa_set_add(batch
->active_queries
, q
);
289 zink_begin_query(struct pipe_context
*pctx
,
290 struct pipe_query
*q
)
292 struct zink_query
*query
= (struct zink_query
*)q
;
293 struct zink_batch
*batch
= zink_curr_batch(zink_context(pctx
));
295 /* ignore begin_query for timestamps */
296 if (query
->type
== PIPE_QUERY_TIMESTAMP
)
298 util_query_clear_result(&query
->accumulated_result
, query
->type
);
300 begin_query(zink_context(pctx
), batch
, query
);
306 end_query(struct zink_context
*ctx
, struct zink_batch
*batch
, struct zink_query
*q
)
308 struct zink_screen
*screen
= zink_screen(ctx
->base
.screen
);
309 assert(q
->type
!= PIPE_QUERY_TIMESTAMP
);
311 if (q
->vkqtype
== VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
)
312 screen
->vk_CmdEndQueryIndexedEXT(batch
->cmdbuf
, q
->query_pool
, q
->curr_query
, q
->index
);
314 vkCmdEndQuery(batch
->cmdbuf
, q
->query_pool
, q
->curr_query
);
315 if (++q
->curr_query
== q
->num_queries
) {
316 /* can't do zink_batch_no_rp here because we might already be inside a zink_batch_no_rp */
318 q
->needs_reset
= true;
320 reset_pool(ctx
, batch
, q
);
325 zink_end_query(struct pipe_context
*pctx
,
326 struct pipe_query
*q
)
328 struct zink_context
*ctx
= zink_context(pctx
);
329 struct zink_query
*query
= (struct zink_query
*)q
;
330 struct zink_batch
*batch
= zink_curr_batch(ctx
);
332 if (query
->type
== PIPE_QUERY_TIMESTAMP
) {
333 assert(query
->curr_query
== 0);
334 vkCmdWriteTimestamp(batch
->cmdbuf
, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
,
335 query
->query_pool
, 0);
336 } else if (query
->active
)
337 end_query(ctx
, batch
, query
);
343 zink_get_query_result(struct pipe_context
*pctx
,
344 struct pipe_query
*q
,
346 union pipe_query_result
*result
)
348 struct zink_query
*query
= (struct zink_query
*)q
;
351 wait_query(pctx
, query
);
353 pctx
->flush(pctx
, NULL
, 0);
354 return get_query_result(pctx
, q
, wait
, result
);
358 zink_suspend_queries(struct zink_context
*ctx
, struct zink_batch
*batch
)
360 if (!batch
->active_queries
)
362 set_foreach(batch
->active_queries
, entry
) {
363 struct zink_query
*query
= (void*)entry
->key
;
364 /* if a query isn't active here then we don't need to reactivate it on the next batch */
366 end_query(ctx
, batch
, query
);
367 /* the fence is going to steal the set off the batch, so we have to copy
368 * the active queries onto a list
370 list_addtail(&query
->active_list
, &ctx
->suspended_queries
);
376 zink_resume_queries(struct zink_context
*ctx
, struct zink_batch
*batch
)
378 struct zink_query
*query
, *next
;
379 LIST_FOR_EACH_ENTRY_SAFE(query
, next
, &ctx
->suspended_queries
, active_list
) {
380 begin_query(ctx
, batch
, query
);
381 list_delinit(&query
->active_list
);
386 zink_set_active_query_state(struct pipe_context
*pctx
, bool enable
)
388 struct zink_context
*ctx
= zink_context(pctx
);
389 ctx
->queries_disabled
= !enable
;
391 struct zink_batch
*batch
= zink_curr_batch(ctx
);
392 if (ctx
->queries_disabled
)
393 zink_suspend_queries(ctx
, batch
);
395 zink_resume_queries(ctx
, batch
);
399 zink_render_condition(struct pipe_context
*pctx
,
400 struct pipe_query
*pquery
,
402 enum pipe_render_cond_flag mode
)
404 struct zink_context
*ctx
= zink_context(pctx
);
405 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
406 struct zink_query
*query
= (struct zink_query
*)pquery
;
407 struct zink_batch
*batch
= zink_batch_no_rp(ctx
);
408 VkQueryResultFlagBits flags
= 0;
411 screen
->vk_CmdEndConditionalRenderingEXT(batch
->cmdbuf
);
415 struct pipe_resource
*pres
;
416 struct zink_resource
*res
;
417 struct pipe_resource templ
= {};
421 templ
.format
= PIPE_FORMAT_R8_UINT
;
422 templ
.target
= PIPE_BUFFER
;
424 /* need to create a vulkan buffer to copy the data into */
425 pres
= pctx
->screen
->resource_create(pctx
->screen
, &templ
);
429 res
= (struct zink_resource
*)pres
;
431 if (mode
== PIPE_RENDER_COND_WAIT
|| mode
== PIPE_RENDER_COND_BY_REGION_WAIT
)
432 flags
|= VK_QUERY_RESULT_WAIT_BIT
;
434 if (query
->use_64bit
)
435 flags
|= VK_QUERY_RESULT_64_BIT
;
436 int num_results
= query
->curr_query
- query
->last_checked_query
;
437 vkCmdCopyQueryPoolResults(batch
->cmdbuf
, query
->query_pool
, query
->last_checked_query
, num_results
,
438 res
->buffer
, 0, 0, flags
);
440 query
->last_checked_query
= query
->curr_query
;
441 VkConditionalRenderingFlagsEXT begin_flags
= 0;
443 begin_flags
= VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT
;
444 VkConditionalRenderingBeginInfoEXT begin_info
= {};
445 begin_info
.sType
= VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT
;
446 begin_info
.buffer
= res
->buffer
;
447 begin_info
.flags
= begin_flags
;
448 screen
->vk_CmdBeginConditionalRenderingEXT(batch
->cmdbuf
, &begin_info
);
450 zink_batch_reference_resoure(batch
, res
);
452 pipe_resource_reference(&pres
, NULL
);
456 zink_context_query_init(struct pipe_context
*pctx
)
458 struct zink_context
*ctx
= zink_context(pctx
);
459 list_inithead(&ctx
->suspended_queries
);
461 pctx
->create_query
= zink_create_query
;
462 pctx
->destroy_query
= zink_destroy_query
;
463 pctx
->begin_query
= zink_begin_query
;
464 pctx
->end_query
= zink_end_query
;
465 pctx
->get_query_result
= zink_get_query_result
;
466 pctx
->set_active_query_state
= zink_set_active_query_state
;
467 pctx
->render_condition
= zink_render_condition
;