1d0050306d1edf11d869ae88d99ba1cb9eb3f586
[mesa.git] / src / gallium / drivers / zink / zink_query.c
1 #include "zink_query.h"
2
3 #include "zink_context.h"
4 #include "zink_resource.h"
5 #include "zink_screen.h"
6
7 #include "util/u_dump.h"
8 #include "util/u_inlines.h"
9 #include "util/u_memory.h"
10
11 struct zink_query {
12 enum pipe_query_type type;
13
14 VkQueryPool query_pool;
15 unsigned curr_query, num_queries;
16
17 VkQueryType vkqtype;
18 bool use_64bit;
19 bool precise;
20
21 struct list_head active_list;
22 };
23
24 static VkQueryType
25 convert_query_type(unsigned query_type, bool *use_64bit, bool *precise)
26 {
27 *use_64bit = false;
28 *precise = false;
29 switch (query_type) {
30 case PIPE_QUERY_OCCLUSION_COUNTER:
31 *precise = true;
32 *use_64bit = true;
33 case PIPE_QUERY_OCCLUSION_PREDICATE:
34 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
35 return VK_QUERY_TYPE_OCCLUSION;
36 case PIPE_QUERY_TIMESTAMP:
37 *use_64bit = true;
38 return VK_QUERY_TYPE_TIMESTAMP;
39 case PIPE_QUERY_PIPELINE_STATISTICS:
40 return VK_QUERY_TYPE_PIPELINE_STATISTICS;
41 default:
42 debug_printf("unknown query: %s\n",
43 util_str_query_type(query_type, true));
44 unreachable("zink: unknown query type");
45 }
46 }
47
48 static struct pipe_query *
49 zink_create_query(struct pipe_context *pctx,
50 unsigned query_type, unsigned index)
51 {
52 struct zink_screen *screen = zink_screen(pctx->screen);
53 struct zink_query *query = CALLOC_STRUCT(zink_query);
54 VkQueryPoolCreateInfo pool_create = {};
55
56 if (!query)
57 return NULL;
58
59 query->type = query_type;
60 query->vkqtype = convert_query_type(query_type, &query->use_64bit, &query->precise);
61 if (query->vkqtype == -1)
62 return NULL;
63
64 query->num_queries = query_type == PIPE_QUERY_TIMESTAMP ? 1 : 100;
65 query->curr_query = 0;
66
67 pool_create.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
68 pool_create.queryType = query->vkqtype;
69 pool_create.queryCount = query->num_queries;
70
71 VkResult status = vkCreateQueryPool(screen->dev, &pool_create, NULL, &query->query_pool);
72 if (status != VK_SUCCESS) {
73 FREE(query);
74 return NULL;
75 }
76 return (struct pipe_query *)query;
77 }
78
79 /* TODO: rework this to be less hammer-ish using deferred destroy */
80 static void
81 wait_query(struct pipe_context *pctx, struct zink_query *query)
82 {
83 struct pipe_fence_handle *fence = NULL;
84
85 pctx->flush(pctx, &fence, PIPE_FLUSH_HINT_FINISH);
86 if (fence) {
87 pctx->screen->fence_finish(pctx->screen, NULL, fence,
88 PIPE_TIMEOUT_INFINITE);
89 pctx->screen->fence_reference(pctx->screen, &fence, NULL);
90 }
91 }
92
93 static void
94 zink_destroy_query(struct pipe_context *pctx,
95 struct pipe_query *q)
96 {
97 struct zink_screen *screen = zink_screen(pctx->screen);
98 struct zink_query *query = (struct zink_query *)q;
99
100 if (!list_is_empty(&query->active_list)) {
101 wait_query(pctx, query);
102 }
103
104 vkDestroyQueryPool(screen->dev, query->query_pool, NULL);
105 FREE(query);
106 }
107
108 static void
109 begin_query(struct zink_batch *batch, struct zink_query *q)
110 {
111 VkQueryControlFlags flags = 0;
112 if (q->precise)
113 flags |= VK_QUERY_CONTROL_PRECISE_BIT;
114
115 vkCmdBeginQuery(batch->cmdbuf, q->query_pool, q->curr_query, flags);
116 }
117
118 static bool
119 zink_begin_query(struct pipe_context *pctx,
120 struct pipe_query *q)
121 {
122 struct zink_context *ctx = zink_context(pctx);
123 struct zink_query *query = (struct zink_query *)q;
124
125 /* ignore begin_query for timestamps */
126 if (query->type == PIPE_QUERY_TIMESTAMP)
127 return true;
128
129 /* TODO: resetting on begin isn't ideal, as it forces render-pass exit...
130 * should instead reset on creation (if possible?)... Or perhaps maintain
131 * the pool in the batch instead?
132 */
133 struct zink_batch *batch = zink_batch_no_rp(zink_context(pctx));
134 vkCmdResetQueryPool(batch->cmdbuf, query->query_pool, 0, MIN2(query->curr_query + 1, query->num_queries));
135 query->curr_query = 0;
136
137 begin_query(batch, query);
138 list_addtail(&query->active_list, &ctx->active_queries);
139
140 return true;
141 }
142
143 static void
144 end_query(struct zink_batch *batch, struct zink_query *q)
145 {
146 assert(q->type != PIPE_QUERY_TIMESTAMP);
147 vkCmdEndQuery(batch->cmdbuf, q->query_pool, q->curr_query);
148 if (++q->curr_query == q->num_queries) {
149 assert(0);
150 /* need to reset pool! */
151 }
152 }
153
154 static bool
155 zink_end_query(struct pipe_context *pctx,
156 struct pipe_query *q)
157 {
158 struct zink_context *ctx = zink_context(pctx);
159 struct zink_batch *batch = zink_curr_batch(ctx);
160 struct zink_query *query = (struct zink_query *)q;
161
162 if (query->type == PIPE_QUERY_TIMESTAMP) {
163 assert(query->curr_query == 0);
164 vkCmdWriteTimestamp(batch->cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
165 query->query_pool, 0);
166 } else {
167 end_query(batch, query);
168 list_delinit(&query->active_list);
169 }
170
171 return true;
172 }
173
174 static bool
175 zink_get_query_result(struct pipe_context *pctx,
176 struct pipe_query *q,
177 bool wait,
178 union pipe_query_result *result)
179 {
180 struct zink_screen *screen = zink_screen(pctx->screen);
181 struct zink_query *query = (struct zink_query *)q;
182 VkQueryResultFlagBits flags = 0;
183
184 if (wait) {
185 wait_query(pctx, query);
186 flags |= VK_QUERY_RESULT_WAIT_BIT;
187 } else
188 pctx->flush(pctx, NULL, 0);
189
190 if (query->use_64bit)
191 flags |= VK_QUERY_RESULT_64_BIT;
192
193 // TODO: handle curr_query > 100
194 // union pipe_query_result results[100];
195 uint64_t results[100];
196 memset(results, 0, sizeof(results));
197 assert(query->curr_query <= ARRAY_SIZE(results));
198 if (vkGetQueryPoolResults(screen->dev, query->query_pool,
199 0, query->curr_query,
200 sizeof(results),
201 results,
202 sizeof(uint64_t),
203 flags) != VK_SUCCESS)
204 return false;
205
206 util_query_clear_result(result, query->type);
207 for (int i = 0; i < query->curr_query; ++i) {
208 switch (query->type) {
209 case PIPE_QUERY_OCCLUSION_PREDICATE:
210 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
211 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
212 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
213 case PIPE_QUERY_GPU_FINISHED:
214 result->b |= results[i] != 0;
215 break;
216
217 case PIPE_QUERY_OCCLUSION_COUNTER:
218 result->u64 += results[i];
219 break;
220
221 default:
222 debug_printf("unhangled query type: %s\n",
223 util_str_query_type(query->type, true));
224 unreachable("unexpected query type");
225 }
226 }
227
228 return TRUE;
229 }
230
231 void
232 zink_suspend_queries(struct zink_context *ctx, struct zink_batch *batch)
233 {
234 struct zink_query *query;
235 LIST_FOR_EACH_ENTRY(query, &ctx->active_queries, active_list) {
236 end_query(batch, query);
237 }
238 }
239
240 void
241 zink_resume_queries(struct zink_context *ctx, struct zink_batch *batch)
242 {
243 struct zink_query *query;
244 LIST_FOR_EACH_ENTRY(query, &ctx->active_queries, active_list) {
245 vkCmdResetQueryPool(batch->cmdbuf, query->query_pool, query->curr_query, 1);
246 begin_query(batch, query);
247 }
248 }
249
250 static void
251 zink_set_active_query_state(struct pipe_context *pctx, bool enable)
252 {
253 struct zink_context *ctx = zink_context(pctx);
254 ctx->queries_disabled = !enable;
255
256 struct zink_batch *batch = zink_curr_batch(ctx);
257 if (ctx->queries_disabled)
258 zink_suspend_queries(ctx, batch);
259 else
260 zink_resume_queries(ctx, batch);
261 }
262
263 static void
264 zink_render_condition(struct pipe_context *pctx,
265 struct pipe_query *pquery,
266 bool condition,
267 enum pipe_render_cond_flag mode)
268 {
269 struct zink_context *ctx = zink_context(pctx);
270 struct zink_screen *screen = zink_screen(pctx->screen);
271 struct zink_query *query = (struct zink_query *)pquery;
272 struct zink_batch *batch = zink_curr_batch(ctx);
273 VkQueryResultFlagBits flags = 0;
274
275 if (query == NULL) {
276 screen->vk_CmdEndConditionalRenderingEXT(batch->cmdbuf);
277 return;
278 }
279
280 struct pipe_resource *pres;
281 struct zink_resource *res;
282 struct pipe_resource templ = {};
283 templ.width0 = 8;
284 templ.height0 = 1;
285 templ.depth0 = 1;
286 templ.format = PIPE_FORMAT_R8_UINT;
287 templ.target = PIPE_BUFFER;
288
289 /* need to create a vulkan buffer to copy the data into */
290 pres = pctx->screen->resource_create(pctx->screen, &templ);
291 if (!pres)
292 return;
293
294 res = (struct zink_resource *)pres;
295
296 if (mode == PIPE_RENDER_COND_WAIT || mode == PIPE_RENDER_COND_BY_REGION_WAIT)
297 flags |= VK_QUERY_RESULT_WAIT_BIT;
298
299 if (query->use_64bit)
300 flags |= VK_QUERY_RESULT_64_BIT;
301 vkCmdCopyQueryPoolResults(batch->cmdbuf, query->query_pool, 0, 1,
302 res->buffer, 0, 0, flags);
303
304 VkConditionalRenderingFlagsEXT begin_flags = 0;
305 if (condition)
306 begin_flags = VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT;
307 VkConditionalRenderingBeginInfoEXT begin_info = {};
308 begin_info.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
309 begin_info.buffer = res->buffer;
310 begin_info.flags = begin_flags;
311 screen->vk_CmdBeginConditionalRenderingEXT(batch->cmdbuf, &begin_info);
312
313 zink_batch_reference_resoure(batch, res);
314
315 pipe_resource_reference(&pres, NULL);
316 }
317
318 void
319 zink_context_query_init(struct pipe_context *pctx)
320 {
321 struct zink_context *ctx = zink_context(pctx);
322 list_inithead(&ctx->active_queries);
323
324 pctx->create_query = zink_create_query;
325 pctx->destroy_query = zink_destroy_query;
326 pctx->begin_query = zink_begin_query;
327 pctx->end_query = zink_end_query;
328 pctx->get_query_result = zink_get_query_result;
329 pctx->set_active_query_state = zink_set_active_query_state;
330 pctx->render_condition = zink_render_condition;
331 }