1 #include "zink_query.h"
3 #include "zink_context.h"
4 #include "zink_resource.h"
5 #include "zink_screen.h"
7 #include "util/u_dump.h"
8 #include "util/u_inlines.h"
9 #include "util/u_memory.h"
12 enum pipe_query_type type
;
14 VkQueryPool query_pool
;
15 unsigned curr_query
, num_queries
;
21 struct list_head active_list
;
25 convert_query_type(unsigned query_type
, bool *use_64bit
, bool *precise
)
30 case PIPE_QUERY_OCCLUSION_COUNTER
:
33 case PIPE_QUERY_OCCLUSION_PREDICATE
:
34 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE
:
35 return VK_QUERY_TYPE_OCCLUSION
;
36 case PIPE_QUERY_TIMESTAMP
:
38 return VK_QUERY_TYPE_TIMESTAMP
;
39 case PIPE_QUERY_PIPELINE_STATISTICS
:
40 return VK_QUERY_TYPE_PIPELINE_STATISTICS
;
42 debug_printf("unknown query: %s\n",
43 util_str_query_type(query_type
, true));
44 unreachable("zink: unknown query type");
48 static struct pipe_query
*
49 zink_create_query(struct pipe_context
*pctx
,
50 unsigned query_type
, unsigned index
)
52 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
53 struct zink_query
*query
= CALLOC_STRUCT(zink_query
);
54 VkQueryPoolCreateInfo pool_create
= {};
59 query
->type
= query_type
;
60 query
->vkqtype
= convert_query_type(query_type
, &query
->use_64bit
, &query
->precise
);
61 if (query
->vkqtype
== -1)
64 query
->num_queries
= query_type
== PIPE_QUERY_TIMESTAMP
? 1 : 100;
65 query
->curr_query
= 0;
67 pool_create
.sType
= VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
;
68 pool_create
.queryType
= query
->vkqtype
;
69 pool_create
.queryCount
= query
->num_queries
;
71 VkResult status
= vkCreateQueryPool(screen
->dev
, &pool_create
, NULL
, &query
->query_pool
);
72 if (status
!= VK_SUCCESS
) {
76 return (struct pipe_query
*)query
;
79 /* TODO: rework this to be less hammer-ish using deferred destroy */
81 wait_query(struct pipe_context
*pctx
, struct zink_query
*query
)
83 struct pipe_fence_handle
*fence
= NULL
;
85 pctx
->flush(pctx
, &fence
, PIPE_FLUSH_HINT_FINISH
);
87 pctx
->screen
->fence_finish(pctx
->screen
, NULL
, fence
,
88 PIPE_TIMEOUT_INFINITE
);
89 pctx
->screen
->fence_reference(pctx
->screen
, &fence
, NULL
);
94 zink_destroy_query(struct pipe_context
*pctx
,
97 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
98 struct zink_query
*query
= (struct zink_query
*)q
;
100 if (!list_is_empty(&query
->active_list
)) {
101 wait_query(pctx
, query
);
104 vkDestroyQueryPool(screen
->dev
, query
->query_pool
, NULL
);
109 begin_query(struct zink_context
*ctx
, struct zink_query
*q
)
111 VkQueryControlFlags flags
= 0;
113 flags
|= VK_QUERY_CONTROL_PRECISE_BIT
;
115 struct zink_batch
*batch
= zink_curr_batch(ctx
);
116 vkCmdBeginQuery(batch
->cmdbuf
, q
->query_pool
, q
->curr_query
, flags
);
120 zink_begin_query(struct pipe_context
*pctx
,
121 struct pipe_query
*q
)
123 struct zink_context
*ctx
= zink_context(pctx
);
124 struct zink_query
*query
= (struct zink_query
*)q
;
126 /* ignore begin_query for timestamps */
127 if (query
->type
== PIPE_QUERY_TIMESTAMP
)
130 /* TODO: resetting on begin isn't ideal, as it forces render-pass exit...
131 * should instead reset on creation (if possible?)... Or perhaps maintain
132 * the pool in the batch instead?
134 struct zink_batch
*batch
= zink_batch_no_rp(zink_context(pctx
));
135 vkCmdResetQueryPool(batch
->cmdbuf
, query
->query_pool
, 0, MIN2(query
->curr_query
+ 1, query
->num_queries
));
136 query
->curr_query
= 0;
138 begin_query(ctx
, query
);
139 list_addtail(&query
->active_list
, &ctx
->active_queries
);
145 end_query(struct zink_context
*ctx
, struct zink_query
*q
)
147 struct zink_batch
*batch
= zink_curr_batch(ctx
);
148 assert(q
->type
!= PIPE_QUERY_TIMESTAMP
);
149 vkCmdEndQuery(batch
->cmdbuf
, q
->query_pool
, q
->curr_query
);
150 if (++q
->curr_query
== q
->num_queries
) {
152 /* need to reset pool! */
157 zink_end_query(struct pipe_context
*pctx
,
158 struct pipe_query
*q
)
160 struct zink_context
*ctx
= zink_context(pctx
);
161 struct zink_query
*query
= (struct zink_query
*)q
;
163 if (query
->type
== PIPE_QUERY_TIMESTAMP
) {
164 assert(query
->curr_query
== 0);
165 struct zink_batch
*batch
= zink_curr_batch(ctx
);
166 vkCmdWriteTimestamp(batch
->cmdbuf
, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
,
167 query
->query_pool
, 0);
169 end_query(ctx
, query
);
170 list_delinit(&query
->active_list
);
177 zink_get_query_result(struct pipe_context
*pctx
,
178 struct pipe_query
*q
,
180 union pipe_query_result
*result
)
182 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
183 struct zink_query
*query
= (struct zink_query
*)q
;
184 VkQueryResultFlagBits flags
= 0;
187 wait_query(pctx
, query
);
188 flags
|= VK_QUERY_RESULT_WAIT_BIT
;
190 pctx
->flush(pctx
, NULL
, 0);
192 if (query
->use_64bit
)
193 flags
|= VK_QUERY_RESULT_64_BIT
;
195 // TODO: handle curr_query > 100
196 // union pipe_query_result results[100];
197 uint64_t results
[100];
198 memset(results
, 0, sizeof(results
));
199 assert(query
->curr_query
<= ARRAY_SIZE(results
));
200 if (vkGetQueryPoolResults(screen
->dev
, query
->query_pool
,
201 0, query
->curr_query
,
205 flags
) != VK_SUCCESS
)
208 util_query_clear_result(result
, query
->type
);
209 for (int i
= 0; i
< query
->curr_query
; ++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
];
224 debug_printf("unhangled query type: %s\n",
225 util_str_query_type(query
->type
, true));
226 unreachable("unexpected query type");
234 zink_suspend_queries(struct zink_context
*ctx
, struct zink_batch
*batch
)
236 struct zink_query
*query
;
237 LIST_FOR_EACH_ENTRY(query
, &ctx
->active_queries
, active_list
) {
238 end_query(ctx
, query
);
243 zink_resume_queries(struct zink_context
*ctx
, struct zink_batch
*batch
)
245 struct zink_query
*query
;
246 LIST_FOR_EACH_ENTRY(query
, &ctx
->active_queries
, active_list
) {
247 vkCmdResetQueryPool(batch
->cmdbuf
, query
->query_pool
, query
->curr_query
, 1);
248 begin_query(ctx
, query
);
253 zink_set_active_query_state(struct pipe_context
*pctx
, bool enable
)
255 struct zink_context
*ctx
= zink_context(pctx
);
256 ctx
->queries_disabled
= !enable
;
258 struct zink_batch
*batch
= zink_curr_batch(ctx
);
259 if (ctx
->queries_disabled
)
260 zink_suspend_queries(ctx
, batch
);
262 zink_resume_queries(ctx
, batch
);
266 zink_render_condition(struct pipe_context
*pctx
,
267 struct pipe_query
*pquery
,
269 enum pipe_render_cond_flag mode
)
271 struct zink_context
*ctx
= zink_context(pctx
);
272 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
273 struct zink_query
*query
= (struct zink_query
*)pquery
;
274 struct zink_batch
*batch
= zink_curr_batch(ctx
);
275 VkQueryResultFlagBits flags
= 0;
278 screen
->vk_CmdEndConditionalRenderingEXT(batch
->cmdbuf
);
282 struct pipe_resource
*pres
;
283 struct zink_resource
*res
;
284 struct pipe_resource templ
= {};
288 templ
.format
= PIPE_FORMAT_R8_UINT
;
289 templ
.target
= PIPE_BUFFER
;
291 /* need to create a vulkan buffer to copy the data into */
292 pres
= pctx
->screen
->resource_create(pctx
->screen
, &templ
);
296 res
= (struct zink_resource
*)pres
;
298 if (mode
== PIPE_RENDER_COND_WAIT
|| mode
== PIPE_RENDER_COND_BY_REGION_WAIT
)
299 flags
|= VK_QUERY_RESULT_WAIT_BIT
;
301 if (query
->use_64bit
)
302 flags
|= VK_QUERY_RESULT_64_BIT
;
303 vkCmdCopyQueryPoolResults(batch
->cmdbuf
, query
->query_pool
, 0, 1,
304 res
->buffer
, 0, 0, flags
);
306 VkConditionalRenderingFlagsEXT begin_flags
= 0;
308 begin_flags
= VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT
;
309 VkConditionalRenderingBeginInfoEXT begin_info
= {};
310 begin_info
.sType
= VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT
;
311 begin_info
.buffer
= res
->buffer
;
312 begin_info
.flags
= begin_flags
;
313 screen
->vk_CmdBeginConditionalRenderingEXT(batch
->cmdbuf
, &begin_info
);
315 zink_batch_reference_resoure(batch
, res
);
317 pipe_resource_reference(&pres
, NULL
);
321 zink_context_query_init(struct pipe_context
*pctx
)
323 struct zink_context
*ctx
= zink_context(pctx
);
324 list_inithead(&ctx
->active_queries
);
326 pctx
->create_query
= zink_create_query
;
327 pctx
->destroy_query
= zink_destroy_query
;
328 pctx
->begin_query
= zink_begin_query
;
329 pctx
->end_query
= zink_end_query
;
330 pctx
->get_query_result
= zink_get_query_result
;
331 pctx
->set_active_query_state
= zink_set_active_query_state
;
332 pctx
->render_condition
= zink_render_condition
;