• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "zink_query.h"
2 
3 #include "zink_context.h"
4 #include "zink_fence.h"
5 #include "zink_resource.h"
6 #include "zink_screen.h"
7 
8 #include "util/hash_table.h"
9 #include "util/set.h"
10 #include "util/u_dump.h"
11 #include "util/u_inlines.h"
12 #include "util/u_memory.h"
13 
14 #if defined(PIPE_ARCH_X86_64) || defined(PIPE_ARCH_PPC_64) || defined(PIPE_ARCH_AARCH64) || defined(PIPE_ARCH_MIPS64)
15 #define NUM_QUERIES 5000
16 #else
17 #define NUM_QUERIES 500
18 #endif
19 
20 struct zink_query_buffer {
21    struct list_head list;
22    unsigned num_results;
23    struct pipe_resource *buffer;
24    struct pipe_resource *xfb_buffers[PIPE_MAX_VERTEX_STREAMS - 1];
25 };
26 
27 struct zink_query {
28    struct threaded_query base;
29    enum pipe_query_type type;
30 
31    VkQueryPool query_pool;
32    VkQueryPool xfb_query_pool[PIPE_MAX_VERTEX_STREAMS - 1]; //stream 0 is in the base pool
33    unsigned curr_query, last_start;
34 
35    VkQueryType vkqtype;
36    unsigned index;
37    bool precise;
38    bool xfb_running;
39    bool xfb_overflow;
40 
41    bool active; /* query is considered active by vk */
42    bool needs_reset; /* query is considered active by vk and cannot be destroyed */
43    bool dead; /* query should be destroyed when its fence finishes */
44    bool needs_update; /* query needs to update its qbos */
45 
46    struct list_head active_list;
47 
48    struct list_head stats_list; /* when active, statistics queries are added to ctx->primitives_generated_queries */
49    bool have_gs[NUM_QUERIES]; /* geometry shaders use GEOMETRY_SHADER_PRIMITIVES_BIT */
50    bool have_xfb[NUM_QUERIES]; /* xfb was active during this query */
51 
52    struct zink_batch_usage *batch_id; //batch that the query was started in
53 
54    struct list_head buffers;
55    union {
56       struct zink_query_buffer *curr_qbo;
57       struct pipe_fence_handle *fence; //PIPE_QUERY_GPU_FINISHED
58    };
59 
60    struct zink_resource *predicate;
61    bool predicate_dirty;
62 };
63 
64 static void
65 update_qbo(struct zink_context *ctx, struct zink_query *q);
66 static void
67 reset_pool(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q);
68 
69 static inline unsigned
get_num_results(enum pipe_query_type query_type)70 get_num_results(enum pipe_query_type query_type)
71 {
72    switch (query_type) {
73    case PIPE_QUERY_OCCLUSION_COUNTER:
74    case PIPE_QUERY_OCCLUSION_PREDICATE:
75    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
76    case PIPE_QUERY_TIME_ELAPSED:
77    case PIPE_QUERY_TIMESTAMP:
78    case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
79       return 1;
80    case PIPE_QUERY_PRIMITIVES_GENERATED:
81    case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
82    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
83    case PIPE_QUERY_PRIMITIVES_EMITTED:
84       return 2;
85    default:
86       debug_printf("unknown query: %s\n",
87                    util_str_query_type(query_type, true));
88       unreachable("zink: unknown query type");
89    }
90 }
91 
92 static VkQueryPipelineStatisticFlags
pipeline_statistic_convert(enum pipe_statistics_query_index idx)93 pipeline_statistic_convert(enum pipe_statistics_query_index idx)
94 {
95    unsigned map[] = {
96       [PIPE_STAT_QUERY_IA_VERTICES] = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT,
97       [PIPE_STAT_QUERY_IA_PRIMITIVES] = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT,
98       [PIPE_STAT_QUERY_VS_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT,
99       [PIPE_STAT_QUERY_GS_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT,
100       [PIPE_STAT_QUERY_GS_PRIMITIVES] = VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT,
101       [PIPE_STAT_QUERY_C_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT,
102       [PIPE_STAT_QUERY_C_PRIMITIVES] = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT,
103       [PIPE_STAT_QUERY_PS_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT,
104       [PIPE_STAT_QUERY_HS_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT,
105       [PIPE_STAT_QUERY_DS_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT,
106       [PIPE_STAT_QUERY_CS_INVOCATIONS] = VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT
107    };
108    assert(idx < ARRAY_SIZE(map));
109    return map[idx];
110 }
111 
112 static void
timestamp_to_nanoseconds(struct zink_screen * screen,uint64_t * timestamp)113 timestamp_to_nanoseconds(struct zink_screen *screen, uint64_t *timestamp)
114 {
115    /* The number of valid bits in a timestamp value is determined by
116     * the VkQueueFamilyProperties::timestampValidBits property of the queue on which the timestamp is written.
117     * - 17.5. Timestamp Queries
118     */
119    if (screen->timestamp_valid_bits < 64)
120       *timestamp &= (1ull << screen->timestamp_valid_bits) - 1;
121 
122    /* The number of nanoseconds it takes for a timestamp value to be incremented by 1
123     * can be obtained from VkPhysicalDeviceLimits::timestampPeriod
124     * - 17.5. Timestamp Queries
125     */
126    *timestamp *= screen->info.props.limits.timestampPeriod;
127 }
128 
129 static VkQueryType
convert_query_type(unsigned query_type,bool * precise)130 convert_query_type(unsigned query_type, bool *precise)
131 {
132    *precise = false;
133    switch (query_type) {
134    case PIPE_QUERY_OCCLUSION_COUNTER:
135       *precise = true;
136       FALLTHROUGH;
137    case PIPE_QUERY_OCCLUSION_PREDICATE:
138    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
139       return VK_QUERY_TYPE_OCCLUSION;
140    case PIPE_QUERY_TIME_ELAPSED:
141    case PIPE_QUERY_TIMESTAMP:
142       return VK_QUERY_TYPE_TIMESTAMP;
143    case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
144    case PIPE_QUERY_PRIMITIVES_GENERATED:
145       return VK_QUERY_TYPE_PIPELINE_STATISTICS;
146    case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
147    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
148    case PIPE_QUERY_PRIMITIVES_EMITTED:
149       return VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
150    default:
151       debug_printf("unknown query: %s\n",
152                    util_str_query_type(query_type, true));
153       unreachable("zink: unknown query type");
154    }
155 }
156 
157 static bool
needs_stats_list(struct zink_query * query)158 needs_stats_list(struct zink_query *query)
159 {
160    return query->type == PIPE_QUERY_PRIMITIVES_GENERATED ||
161           query->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE ||
162           query->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE;
163 }
164 
165 static bool
is_time_query(struct zink_query * query)166 is_time_query(struct zink_query *query)
167 {
168    return query->type == PIPE_QUERY_TIMESTAMP || query->type == PIPE_QUERY_TIME_ELAPSED;
169 }
170 
171 static bool
is_so_overflow_query(struct zink_query * query)172 is_so_overflow_query(struct zink_query *query)
173 {
174    return query->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE || query->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE;
175 }
176 
177 static bool
is_bool_query(struct zink_query * query)178 is_bool_query(struct zink_query *query)
179 {
180    return is_so_overflow_query(query) ||
181           query->type == PIPE_QUERY_OCCLUSION_PREDICATE ||
182           query->type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE ||
183           query->type == PIPE_QUERY_GPU_FINISHED;
184 }
185 
186 static void
qbo_sync_from_prev(struct zink_context * ctx,struct zink_query * query,unsigned id_offset,unsigned last_start)187 qbo_sync_from_prev(struct zink_context *ctx, struct zink_query *query, unsigned id_offset, unsigned last_start)
188 {
189    assert(id_offset);
190 
191    struct zink_query_buffer *prev = list_last_entry(&query->buffers, struct zink_query_buffer, list);
192    unsigned result_size = get_num_results(query->type) * sizeof(uint64_t);
193    /* this is get_buffer_offset() but without the zink_query object */
194    unsigned qbo_offset = last_start * get_num_results(query->type) * sizeof(uint64_t);
195    query->curr_query = id_offset;
196    query->curr_qbo->num_results = id_offset;
197    zink_copy_buffer(ctx, zink_resource(query->curr_qbo->buffer), zink_resource(prev->buffer), 0,
198                     qbo_offset,
199                     id_offset * result_size);
200 }
201 
202 static bool
qbo_append(struct pipe_screen * screen,struct zink_query * query)203 qbo_append(struct pipe_screen *screen, struct zink_query *query)
204 {
205    if (query->curr_qbo && query->curr_qbo->list.next)
206       return true;
207    struct zink_query_buffer *qbo = CALLOC_STRUCT(zink_query_buffer);
208    if (!qbo)
209       return false;
210    qbo->buffer = pipe_buffer_create(screen, PIPE_BIND_QUERY_BUFFER,
211                                   PIPE_USAGE_STAGING,
212                                   /* this is the maximum possible size of the results in a given buffer */
213                                   NUM_QUERIES * get_num_results(query->type) * sizeof(uint64_t));
214    if (!qbo->buffer)
215       goto fail;
216    if (query->type == PIPE_QUERY_PRIMITIVES_GENERATED) {
217       /* need separate xfb buffer */
218       qbo->xfb_buffers[0] = pipe_buffer_create(screen, PIPE_BIND_QUERY_BUFFER,
219                                      PIPE_USAGE_STAGING,
220                                      /* this is the maximum possible size of the results in a given buffer */
221                                      NUM_QUERIES * get_num_results(query->type) * sizeof(uint64_t));
222       if (!qbo->xfb_buffers[0])
223          goto fail;
224    } else if (query->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
225       /* need to monitor all xfb streams */
226       for (unsigned i = 0; i < ARRAY_SIZE(qbo->xfb_buffers); i++) {
227          /* need separate xfb buffer */
228          qbo->xfb_buffers[i] = pipe_buffer_create(screen, PIPE_BIND_QUERY_BUFFER,
229                                         PIPE_USAGE_STAGING,
230                                         /* this is the maximum possible size of the results in a given buffer */
231                                         NUM_QUERIES * get_num_results(query->type) * sizeof(uint64_t));
232          if (!qbo->xfb_buffers[i])
233             goto fail;
234       }
235    }
236    list_addtail(&qbo->list, &query->buffers);
237 
238    return true;
239 fail:
240    pipe_resource_reference(&qbo->buffer, NULL);
241    for (unsigned i = 0; i < ARRAY_SIZE(qbo->xfb_buffers); i++)
242       pipe_resource_reference(&qbo->xfb_buffers[i], NULL);
243    FREE(qbo);
244    return false;
245 }
246 
247 static void
destroy_query(struct zink_screen * screen,struct zink_query * query)248 destroy_query(struct zink_screen *screen, struct zink_query *query)
249 {
250    assert(zink_screen_usage_check_completion(screen, query->batch_id));
251    if (query->query_pool)
252       VKSCR(DestroyQueryPool)(screen->dev, query->query_pool, NULL);
253    struct zink_query_buffer *qbo, *next;
254    LIST_FOR_EACH_ENTRY_SAFE(qbo, next, &query->buffers, list) {
255       pipe_resource_reference(&qbo->buffer, NULL);
256       for (unsigned i = 0; i < ARRAY_SIZE(qbo->xfb_buffers); i++)
257          pipe_resource_reference(&qbo->xfb_buffers[i], NULL);
258       FREE(qbo);
259    }
260    for (unsigned i = 0; i < ARRAY_SIZE(query->xfb_query_pool); i++) {
261       if (query->xfb_query_pool[i])
262          VKSCR(DestroyQueryPool)(screen->dev, query->xfb_query_pool[i], NULL);
263    }
264    pipe_resource_reference((struct pipe_resource**)&query->predicate, NULL);
265    FREE(query);
266 }
267 
268 static void
reset_qbo(struct zink_query * q)269 reset_qbo(struct zink_query *q)
270 {
271    q->curr_qbo = list_first_entry(&q->buffers, struct zink_query_buffer, list);
272    q->curr_qbo->num_results = 0;
273 }
274 
275 static struct pipe_query *
zink_create_query(struct pipe_context * pctx,unsigned query_type,unsigned index)276 zink_create_query(struct pipe_context *pctx,
277                   unsigned query_type, unsigned index)
278 {
279    struct zink_screen *screen = zink_screen(pctx->screen);
280    struct zink_query *query = CALLOC_STRUCT(zink_query);
281    VkQueryPoolCreateInfo pool_create = {0};
282 
283    if (!query)
284       return NULL;
285    list_inithead(&query->buffers);
286 
287    query->index = index;
288    query->type = query_type;
289    if (query->type == PIPE_QUERY_GPU_FINISHED)
290       return (struct pipe_query *)query;
291    query->vkqtype = convert_query_type(query_type, &query->precise);
292    if (query->vkqtype == -1)
293       return NULL;
294 
295    assert(!query->precise || query->vkqtype == VK_QUERY_TYPE_OCCLUSION);
296 
297    query->curr_query = 0;
298 
299    pool_create.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
300    pool_create.queryType = query->vkqtype;
301    pool_create.queryCount = NUM_QUERIES;
302    if (query_type == PIPE_QUERY_PRIMITIVES_GENERATED)
303      pool_create.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT |
304                                       VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT;
305    else if (query_type == PIPE_QUERY_PIPELINE_STATISTICS_SINGLE)
306       pool_create.pipelineStatistics = pipeline_statistic_convert(index);
307 
308    VkResult status = VKSCR(CreateQueryPool)(screen->dev, &pool_create, NULL, &query->query_pool);
309    if (status != VK_SUCCESS)
310       goto fail;
311    if (query_type == PIPE_QUERY_PRIMITIVES_GENERATED) {
312       /* if xfb is active, we need to use an xfb query, otherwise we need pipeline statistics */
313       pool_create.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
314       pool_create.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
315       pool_create.queryCount = NUM_QUERIES;
316 
317       status = VKSCR(CreateQueryPool)(screen->dev, &pool_create, NULL, &query->xfb_query_pool[0]);
318       if (status != VK_SUCCESS)
319          goto fail;
320    } else if (query_type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
321       /* need to monitor all xfb streams */
322       for (unsigned i = 0; i < ARRAY_SIZE(query->xfb_query_pool); i++) {
323          status = VKSCR(CreateQueryPool)(screen->dev, &pool_create, NULL, &query->xfb_query_pool[i]);
324          if (status != VK_SUCCESS)
325             goto fail;
326       }
327    }
328    if (!qbo_append(pctx->screen, query))
329       goto fail;
330    struct zink_batch *batch = &zink_context(pctx)->batch;
331    batch->has_work = true;
332    query->needs_reset = true;
333    if (query->type == PIPE_QUERY_TIMESTAMP) {
334       query->active = true;
335       /* defer pool reset until end_query since we're guaranteed to be threadsafe then */
336       reset_qbo(query);
337    }
338    return (struct pipe_query *)query;
339 fail:
340    destroy_query(screen, query);
341    return NULL;
342 }
343 
344 static void
zink_destroy_query(struct pipe_context * pctx,struct pipe_query * q)345 zink_destroy_query(struct pipe_context *pctx,
346                    struct pipe_query *q)
347 {
348    struct zink_screen *screen = zink_screen(pctx->screen);
349    struct zink_query *query = (struct zink_query *)q;
350 
351    /* only destroy if this query isn't active on any batches,
352     * otherwise just mark dead and wait
353     */
354    if (query->batch_id) {
355       p_atomic_set(&query->dead, true);
356       return;
357    }
358 
359    destroy_query(screen, query);
360 }
361 
362 void
zink_prune_query(struct zink_screen * screen,struct zink_batch_state * bs,struct zink_query * query)363 zink_prune_query(struct zink_screen *screen, struct zink_batch_state *bs, struct zink_query *query)
364 {
365    if (!zink_batch_usage_matches(query->batch_id, bs))
366       return;
367    query->batch_id = NULL;
368    if (p_atomic_read(&query->dead))
369       destroy_query(screen, query);
370 }
371 
372 static void
check_query_results(struct zink_query * query,union pipe_query_result * result,int num_results,uint64_t * results,uint64_t * xfb_results)373 check_query_results(struct zink_query *query, union pipe_query_result *result,
374                     int num_results, uint64_t *results, uint64_t *xfb_results)
375 {
376    uint64_t last_val = 0;
377    int result_size = get_num_results(query->type);
378    for (int i = 0; i < num_results * result_size; i += result_size) {
379       switch (query->type) {
380       case PIPE_QUERY_OCCLUSION_PREDICATE:
381       case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
382       case PIPE_QUERY_GPU_FINISHED:
383          result->b |= results[i] != 0;
384          break;
385 
386       case PIPE_QUERY_TIME_ELAPSED:
387       case PIPE_QUERY_TIMESTAMP:
388          /* the application can sum the differences between all N queries to determine the total execution time.
389           * - 17.5. Timestamp Queries
390           */
391          if (query->type != PIPE_QUERY_TIME_ELAPSED || i)
392             result->u64 += results[i] - last_val;
393          last_val = results[i];
394          break;
395       case PIPE_QUERY_OCCLUSION_COUNTER:
396          result->u64 += results[i];
397          break;
398       case PIPE_QUERY_PRIMITIVES_GENERATED:
399          if (query->have_xfb[query->last_start + i / 2] || query->index)
400             result->u64 += xfb_results[i + 1];
401          else
402             /* if a given draw had a geometry shader, we need to use the second result */
403             result->u64 += results[i + query->have_gs[query->last_start + i / 2]];
404          break;
405       case PIPE_QUERY_PRIMITIVES_EMITTED:
406          /* A query pool created with this type will capture 2 integers -
407           * numPrimitivesWritten and numPrimitivesNeeded -
408           * for the specified vertex stream output from the last vertex processing stage.
409           * - from VK_EXT_transform_feedback spec
410           */
411          result->u64 += results[i];
412          break;
413       case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
414       case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
415          /* A query pool created with this type will capture 2 integers -
416           * numPrimitivesWritten and numPrimitivesNeeded -
417           * for the specified vertex stream output from the last vertex processing stage.
418           * - from VK_EXT_transform_feedback spec
419           */
420          if (query->have_xfb[query->last_start + i / 2])
421             result->b |= results[i] != results[i + 1];
422          break;
423       case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
424          result->u64 += results[i];
425          break;
426 
427       default:
428          debug_printf("unhandled query type: %s\n",
429                       util_str_query_type(query->type, true));
430          unreachable("unexpected query type");
431       }
432    }
433 }
434 
435 static bool
get_query_result(struct pipe_context * pctx,struct pipe_query * q,bool wait,union pipe_query_result * result)436 get_query_result(struct pipe_context *pctx,
437                       struct pipe_query *q,
438                       bool wait,
439                       union pipe_query_result *result)
440 {
441    struct zink_screen *screen = zink_screen(pctx->screen);
442    struct zink_query *query = (struct zink_query *)q;
443    unsigned flags = PIPE_MAP_READ;
444 
445    if (!wait)
446       flags |= PIPE_MAP_DONTBLOCK;
447    if (query->base.flushed)
448       /* this is not a context-safe operation; ensure map doesn't use slab alloc */
449       flags |= PIPE_MAP_THREAD_SAFE;
450 
451    util_query_clear_result(result, query->type);
452 
453    int num_results = query->curr_query - query->last_start;
454    int result_size = get_num_results(query->type) * sizeof(uint64_t);
455 
456    struct zink_query_buffer *qbo;
457    struct pipe_transfer *xfer;
458    LIST_FOR_EACH_ENTRY(qbo, &query->buffers, list) {
459       uint64_t *xfb_results = NULL;
460       uint64_t *results;
461       bool is_timestamp = query->type == PIPE_QUERY_TIMESTAMP || query->type == PIPE_QUERY_TIMESTAMP_DISJOINT;
462       results = pipe_buffer_map_range(pctx, qbo->buffer, 0,
463                                       (is_timestamp ? 1 : qbo->num_results) * result_size, flags, &xfer);
464       if (!results) {
465          if (wait)
466             debug_printf("zink: qbo read failed!");
467          return false;
468       }
469       struct pipe_transfer *xfb_xfer = NULL;
470       if (query->type == PIPE_QUERY_PRIMITIVES_GENERATED) {
471          xfb_results = pipe_buffer_map_range(pctx, qbo->xfb_buffers[0], 0,
472                                          qbo->num_results * result_size, flags, &xfb_xfer);
473          if (!xfb_results) {
474             if (wait)
475                debug_printf("zink: xfb qbo read failed!");
476             pipe_buffer_unmap(pctx, xfer);
477             return false;
478          }
479       }
480       check_query_results(query, result, is_timestamp ? 1 : qbo->num_results, results, xfb_results);
481       pipe_buffer_unmap(pctx, xfer);
482       if (xfb_xfer)
483          pipe_buffer_unmap(pctx, xfb_xfer);
484       if (query->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
485          for (unsigned i = 0; i < ARRAY_SIZE(qbo->xfb_buffers) && !result->b; i++) {
486             uint64_t *results = pipe_buffer_map_range(pctx, qbo->xfb_buffers[i],
487                                               0,
488                                               qbo->num_results * result_size, flags, &xfer);
489             if (!results) {
490                if (wait)
491                   debug_printf("zink: qbo read failed!");
492                return false;
493             }
494             check_query_results(query, result, num_results, results, xfb_results);
495             pipe_buffer_unmap(pctx, xfer);
496          }
497          /* if overflow is detected we can stop */
498          if (result->b)
499             break;
500       }
501    }
502 
503    if (is_time_query(query))
504       timestamp_to_nanoseconds(screen, &result->u64);
505 
506    return true;
507 }
508 
509 static void
force_cpu_read(struct zink_context * ctx,struct pipe_query * pquery,enum pipe_query_value_type result_type,struct pipe_resource * pres,unsigned offset)510 force_cpu_read(struct zink_context *ctx, struct pipe_query *pquery, enum pipe_query_value_type result_type, struct pipe_resource *pres, unsigned offset)
511 {
512    struct pipe_context *pctx = &ctx->base;
513    unsigned result_size = result_type <= PIPE_QUERY_TYPE_U32 ? sizeof(uint32_t) : sizeof(uint64_t);
514    struct zink_query *query = (struct zink_query*)pquery;
515    union pipe_query_result result;
516 
517    if (query->needs_update)
518       update_qbo(ctx, query);
519 
520    bool success = get_query_result(pctx, pquery, true, &result);
521    if (!success) {
522       debug_printf("zink: getting query result failed\n");
523       return;
524    }
525 
526    if (result_type <= PIPE_QUERY_TYPE_U32) {
527       uint32_t u32;
528       uint32_t limit;
529       if (result_type == PIPE_QUERY_TYPE_I32)
530          limit = INT_MAX;
531       else
532          limit = UINT_MAX;
533       if (is_bool_query(query))
534          u32 = result.b;
535       else
536          u32 = MIN2(limit, result.u64);
537       pipe_buffer_write(pctx, pres, offset, result_size, &u32);
538    } else {
539       uint64_t u64;
540       if (is_bool_query(query))
541          u64 = result.b;
542       else
543          u64 = result.u64;
544       pipe_buffer_write(pctx, pres, offset, result_size, &u64);
545    }
546 }
547 
548 static void
copy_pool_results_to_buffer(struct zink_context * ctx,struct zink_query * query,VkQueryPool pool,unsigned query_id,struct zink_resource * res,unsigned offset,int num_results,VkQueryResultFlags flags)549 copy_pool_results_to_buffer(struct zink_context *ctx, struct zink_query *query, VkQueryPool pool,
550                             unsigned query_id, struct zink_resource *res, unsigned offset,
551                             int num_results, VkQueryResultFlags flags)
552 {
553    struct zink_batch *batch = &ctx->batch;
554    unsigned type_size = (flags & VK_QUERY_RESULT_64_BIT) ? sizeof(uint64_t) : sizeof(uint32_t);
555    unsigned base_result_size = get_num_results(query->type) * type_size;
556    unsigned result_size = base_result_size * num_results;
557    if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
558       result_size += type_size;
559    zink_batch_no_rp(ctx);
560    /* if it's a single query that doesn't need special handling, we can copy it and be done */
561    zink_batch_reference_resource_rw(batch, res, true);
562    zink_resource_buffer_barrier(ctx, res, VK_ACCESS_TRANSFER_WRITE_BIT, 0);
563    util_range_add(&res->base.b, &res->valid_buffer_range, offset, offset + result_size);
564    assert(query_id < NUM_QUERIES);
565    VKCTX(CmdCopyQueryPoolResults)(batch->state->cmdbuf, pool, query_id, num_results, res->obj->buffer,
566                              offset, type_size, flags);
567 }
568 
569 static void
copy_results_to_buffer(struct zink_context * ctx,struct zink_query * query,struct zink_resource * res,unsigned offset,int num_results,VkQueryResultFlags flags)570 copy_results_to_buffer(struct zink_context *ctx, struct zink_query *query, struct zink_resource *res, unsigned offset, int num_results, VkQueryResultFlags flags)
571 {
572    copy_pool_results_to_buffer(ctx, query, query->query_pool, query->last_start, res, offset, num_results, flags);
573 }
574 
575 static void
reset_pool(struct zink_context * ctx,struct zink_batch * batch,struct zink_query * q)576 reset_pool(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q)
577 {
578    unsigned last_start = q->last_start;
579    unsigned id_offset = q->curr_query - q->last_start;
580    /* This command must only be called outside of a render pass instance
581     *
582     * - vkCmdResetQueryPool spec
583     */
584    zink_batch_no_rp(ctx);
585    if (q->needs_update)
586       update_qbo(ctx, q);
587 
588    VKCTX(CmdResetQueryPool)(batch->state->cmdbuf, q->query_pool, 0, NUM_QUERIES);
589    if (q->type == PIPE_QUERY_PRIMITIVES_GENERATED)
590       VKCTX(CmdResetQueryPool)(batch->state->cmdbuf, q->xfb_query_pool[0], 0, NUM_QUERIES);
591    else if (q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
592       for (unsigned i = 0; i < ARRAY_SIZE(q->xfb_query_pool); i++)
593          VKCTX(CmdResetQueryPool)(batch->state->cmdbuf, q->xfb_query_pool[i], 0, NUM_QUERIES);
594    }
595    memset(q->have_gs, 0, sizeof(q->have_gs));
596    memset(q->have_xfb, 0, sizeof(q->have_xfb));
597    q->last_start = q->curr_query = 0;
598    q->needs_reset = false;
599    /* create new qbo for non-timestamp queries:
600     * timestamp queries should never need more than 2 entries in the qbo
601     */
602    if (q->type == PIPE_QUERY_TIMESTAMP)
603       return;
604    if (qbo_append(ctx->base.screen, q))
605       reset_qbo(q);
606    else
607       debug_printf("zink: qbo alloc failed on reset!");
608    if (id_offset)
609       qbo_sync_from_prev(ctx, q, id_offset, last_start);
610 }
611 
612 static inline unsigned
get_buffer_offset(struct zink_query * q,struct pipe_resource * pres,unsigned query_id)613 get_buffer_offset(struct zink_query *q, struct pipe_resource *pres, unsigned query_id)
614 {
615    return (query_id - q->last_start) * get_num_results(q->type) * sizeof(uint64_t);
616 }
617 
618 static void
update_qbo(struct zink_context * ctx,struct zink_query * q)619 update_qbo(struct zink_context *ctx, struct zink_query *q)
620 {
621    struct zink_query_buffer *qbo = q->curr_qbo;
622    unsigned offset = 0;
623    uint32_t query_id = q->curr_query - 1;
624    bool is_timestamp = q->type == PIPE_QUERY_TIMESTAMP || q->type == PIPE_QUERY_TIMESTAMP_DISJOINT;
625    /* timestamp queries just write to offset 0 always */
626    if (!is_timestamp)
627       offset = get_buffer_offset(q, qbo->buffer, query_id);
628    copy_pool_results_to_buffer(ctx, q, q->query_pool, query_id, zink_resource(qbo->buffer),
629                           offset,
630                           1, VK_QUERY_RESULT_64_BIT);
631 
632    if (q->type == PIPE_QUERY_PRIMITIVES_EMITTED ||
633        q->type == PIPE_QUERY_PRIMITIVES_GENERATED ||
634        q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE) {
635       copy_pool_results_to_buffer(ctx, q,
636                                   q->xfb_query_pool[0] ? q->xfb_query_pool[0] : q->query_pool,
637                                   query_id,
638                                   zink_resource(qbo->xfb_buffers[0] ? qbo->xfb_buffers[0] : qbo->buffer),
639                              get_buffer_offset(q, qbo->xfb_buffers[0] ? qbo->xfb_buffers[0] : qbo->buffer, query_id),
640                              1, VK_QUERY_RESULT_64_BIT);
641    }
642 
643    else if (q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
644       for (unsigned i = 0; i < ARRAY_SIZE(q->xfb_query_pool); i++) {
645          copy_pool_results_to_buffer(ctx, q, q->xfb_query_pool[i], query_id, zink_resource(qbo->xfb_buffers[i]),
646                                 get_buffer_offset(q, qbo->xfb_buffers[i], query_id),
647                                 1, VK_QUERY_RESULT_64_BIT);
648       }
649    }
650 
651    if (!is_timestamp)
652       q->curr_qbo->num_results++;
653    q->needs_update = false;
654 }
655 
656 static void
begin_query(struct zink_context * ctx,struct zink_batch * batch,struct zink_query * q)657 begin_query(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q)
658 {
659    VkQueryControlFlags flags = 0;
660 
661    q->predicate_dirty = true;
662    if (q->needs_reset)
663       reset_pool(ctx, batch, q);
664    assert(q->curr_query < NUM_QUERIES);
665    q->active = true;
666    batch->has_work = true;
667    if (q->type == PIPE_QUERY_TIME_ELAPSED) {
668       VKCTX(CmdWriteTimestamp)(batch->state->cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, q->query_pool, q->curr_query);
669       q->curr_query++;
670       update_qbo(ctx, q);
671       zink_batch_usage_set(&q->batch_id, batch->state);
672       _mesa_set_add(batch->state->active_queries, q);
673    }
674    /* ignore the rest of begin_query for timestamps */
675    if (is_time_query(q))
676       return;
677    if (q->precise)
678       flags |= VK_QUERY_CONTROL_PRECISE_BIT;
679    if (q->type == PIPE_QUERY_PRIMITIVES_EMITTED ||
680        q->type == PIPE_QUERY_PRIMITIVES_GENERATED ||
681        q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE) {
682       VKCTX(CmdBeginQueryIndexedEXT)(batch->state->cmdbuf,
683                                      q->xfb_query_pool[0] ? q->xfb_query_pool[0] : q->query_pool,
684                                      q->curr_query,
685                                      flags,
686                                      q->index);
687       q->xfb_running = true;
688    } else if (q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
689       VKCTX(CmdBeginQueryIndexedEXT)(batch->state->cmdbuf,
690                                      q->query_pool,
691                                      q->curr_query,
692                                      flags,
693                                      0);
694       for (unsigned i = 0; i < ARRAY_SIZE(q->xfb_query_pool); i++)
695          VKCTX(CmdBeginQueryIndexedEXT)(batch->state->cmdbuf,
696                                         q->xfb_query_pool[i],
697                                         q->curr_query,
698                                         flags,
699                                         i + 1);
700       q->xfb_running = true;
701    }
702    if (q->vkqtype != VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT)
703       VKCTX(CmdBeginQuery)(batch->state->cmdbuf, q->query_pool, q->curr_query, flags);
704    if (needs_stats_list(q))
705       list_addtail(&q->stats_list, &ctx->primitives_generated_queries);
706    zink_batch_usage_set(&q->batch_id, batch->state);
707    _mesa_set_add(batch->state->active_queries, q);
708 }
709 
710 static bool
zink_begin_query(struct pipe_context * pctx,struct pipe_query * q)711 zink_begin_query(struct pipe_context *pctx,
712                  struct pipe_query *q)
713 {
714    struct zink_query *query = (struct zink_query *)q;
715    struct zink_context *ctx = zink_context(pctx);
716    struct zink_batch *batch = &ctx->batch;
717 
718    query->last_start = query->curr_query;
719    /* drop all past results */
720    reset_qbo(query);
721 
722    begin_query(ctx, batch, query);
723 
724    return true;
725 }
726 
727 static void
update_query_id(struct zink_context * ctx,struct zink_query * q)728 update_query_id(struct zink_context *ctx, struct zink_query *q)
729 {
730    if (++q->curr_query == NUM_QUERIES) {
731       /* always reset on start; this ensures we can actually submit the batch that the current query is on */
732       q->needs_reset = true;
733    }
734    ctx->batch.has_work = true;
735 
736    if (ctx->batch.in_rp)
737       q->needs_update = true;
738    else
739       update_qbo(ctx, q);
740 }
741 
742 static void
end_query(struct zink_context * ctx,struct zink_batch * batch,struct zink_query * q)743 end_query(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q)
744 {
745    ASSERTED struct zink_query_buffer *qbo = q->curr_qbo;
746    assert(qbo);
747    assert(!is_time_query(q));
748    q->active = false;
749    if (q->type == PIPE_QUERY_PRIMITIVES_EMITTED ||
750             q->type == PIPE_QUERY_PRIMITIVES_GENERATED ||
751             q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE) {
752       VKCTX(CmdEndQueryIndexedEXT)(batch->state->cmdbuf,
753                                    q->xfb_query_pool[0] ? q->xfb_query_pool[0] : q->query_pool,
754                                    q->curr_query, q->index);
755    }
756 
757    else if (q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
758       VKCTX(CmdEndQueryIndexedEXT)(batch->state->cmdbuf, q->query_pool, q->curr_query, 0);
759       for (unsigned i = 0; i < ARRAY_SIZE(q->xfb_query_pool); i++) {
760          VKCTX(CmdEndQueryIndexedEXT)(batch->state->cmdbuf, q->xfb_query_pool[i], q->curr_query, i + 1);
761       }
762    }
763    if (q->vkqtype != VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT && !is_time_query(q))
764       VKCTX(CmdEndQuery)(batch->state->cmdbuf, q->query_pool, q->curr_query);
765 
766    if (needs_stats_list(q))
767       list_delinit(&q->stats_list);
768 
769    update_query_id(ctx, q);
770 }
771 
772 static bool
zink_end_query(struct pipe_context * pctx,struct pipe_query * q)773 zink_end_query(struct pipe_context *pctx,
774                struct pipe_query *q)
775 {
776    struct zink_context *ctx = zink_context(pctx);
777    struct zink_query *query = (struct zink_query *)q;
778    struct zink_batch *batch = &ctx->batch;
779 
780    if (query->type == PIPE_QUERY_GPU_FINISHED) {
781       pctx->flush(pctx, &query->fence, PIPE_FLUSH_DEFERRED);
782       return true;
783    }
784 
785    /* FIXME: this can be called from a thread, but it needs to write to the cmdbuf */
786    threaded_context_unwrap_sync(pctx);
787 
788    if (needs_stats_list(query))
789       list_delinit(&query->stats_list);
790    if (is_time_query(query)) {
791       if (query->needs_reset)
792          reset_pool(ctx, batch, query);
793       VKCTX(CmdWriteTimestamp)(batch->state->cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
794                           query->query_pool, query->curr_query);
795       zink_batch_usage_set(&query->batch_id, batch->state);
796       _mesa_set_add(batch->state->active_queries, query);
797       update_query_id(ctx, query);
798    } else if (query->active)
799       end_query(ctx, batch, query);
800 
801    return true;
802 }
803 
804 static bool
zink_get_query_result(struct pipe_context * pctx,struct pipe_query * q,bool wait,union pipe_query_result * result)805 zink_get_query_result(struct pipe_context *pctx,
806                       struct pipe_query *q,
807                       bool wait,
808                       union pipe_query_result *result)
809 {
810    struct zink_query *query = (void*)q;
811    struct zink_context *ctx = zink_context(pctx);
812 
813    if (query->type == PIPE_QUERY_GPU_FINISHED) {
814       struct pipe_screen *screen = pctx->screen;
815 
816       result->b = screen->fence_finish(screen, query->base.flushed ? NULL : pctx,
817                                         query->fence, wait ? PIPE_TIMEOUT_INFINITE : 0);
818       return result->b;
819    }
820 
821    if (query->needs_update)
822       update_qbo(ctx, query);
823 
824    if (zink_batch_usage_is_unflushed(query->batch_id)) {
825       if (!threaded_query(q)->flushed)
826          pctx->flush(pctx, NULL, 0);
827       if (!wait)
828          return false;
829    } else if (!threaded_query(q)->flushed &&
830               /* timeline drivers can wait during buffer map */
831               !zink_screen(pctx->screen)->info.have_KHR_timeline_semaphore)
832       zink_batch_usage_check_completion(ctx, query->batch_id);
833 
834    return get_query_result(pctx, q, wait, result);
835 }
836 
837 void
zink_suspend_queries(struct zink_context * ctx,struct zink_batch * batch)838 zink_suspend_queries(struct zink_context *ctx, struct zink_batch *batch)
839 {
840    set_foreach(batch->state->active_queries, entry) {
841       struct zink_query *query = (void*)entry->key;
842       /* if a query isn't active here then we don't need to reactivate it on the next batch */
843       if (query->active && !is_time_query(query)) {
844          end_query(ctx, batch, query);
845          /* the fence is going to steal the set off the batch, so we have to copy
846           * the active queries onto a list
847           */
848          list_addtail(&query->active_list, &ctx->suspended_queries);
849       }
850       if (query->needs_update)
851          update_qbo(ctx, query);
852       if (query->last_start && query->curr_query > NUM_QUERIES / 2)
853          reset_pool(ctx, batch, query);
854    }
855 }
856 
857 void
zink_resume_queries(struct zink_context * ctx,struct zink_batch * batch)858 zink_resume_queries(struct zink_context *ctx, struct zink_batch *batch)
859 {
860    struct zink_query *query, *next;
861    LIST_FOR_EACH_ENTRY_SAFE(query, next, &ctx->suspended_queries, active_list) {
862       begin_query(ctx, batch, query);
863       list_delinit(&query->active_list);
864    }
865 }
866 
867 void
zink_query_update_gs_states(struct zink_context * ctx)868 zink_query_update_gs_states(struct zink_context *ctx)
869 {
870    struct zink_query *query;
871    LIST_FOR_EACH_ENTRY(query, &ctx->primitives_generated_queries, stats_list) {
872       assert(query->curr_query < ARRAY_SIZE(query->have_gs));
873       assert(query->active);
874       query->have_gs[query->curr_query] = !!ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
875       query->have_xfb[query->curr_query] = !!ctx->num_so_targets;
876    }
877 }
878 
879 static void
zink_set_active_query_state(struct pipe_context * pctx,bool enable)880 zink_set_active_query_state(struct pipe_context *pctx, bool enable)
881 {
882    struct zink_context *ctx = zink_context(pctx);
883    ctx->queries_disabled = !enable;
884 
885    struct zink_batch *batch = &ctx->batch;
886    if (ctx->queries_disabled)
887       zink_suspend_queries(ctx, batch);
888    else
889       zink_resume_queries(ctx, batch);
890 }
891 
892 void
zink_start_conditional_render(struct zink_context * ctx)893 zink_start_conditional_render(struct zink_context *ctx)
894 {
895    if (unlikely(!zink_screen(ctx->base.screen)->info.have_EXT_conditional_rendering))
896       return;
897    struct zink_batch *batch = &ctx->batch;
898    VkConditionalRenderingFlagsEXT begin_flags = 0;
899    if (ctx->render_condition.inverted)
900       begin_flags = VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT;
901    VkConditionalRenderingBeginInfoEXT begin_info = {0};
902    begin_info.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
903    begin_info.buffer = ctx->render_condition.query->predicate->obj->buffer;
904    begin_info.flags = begin_flags;
905    VKCTX(CmdBeginConditionalRenderingEXT)(batch->state->cmdbuf, &begin_info);
906    zink_batch_reference_resource_rw(batch, ctx->render_condition.query->predicate, false);
907 }
908 
909 void
zink_stop_conditional_render(struct zink_context * ctx)910 zink_stop_conditional_render(struct zink_context *ctx)
911 {
912    struct zink_batch *batch = &ctx->batch;
913    zink_clear_apply_conditionals(ctx);
914    if (unlikely(!zink_screen(ctx->base.screen)->info.have_EXT_conditional_rendering))
915       return;
916    VKCTX(CmdEndConditionalRenderingEXT)(batch->state->cmdbuf);
917 }
918 
919 bool
zink_check_conditional_render(struct zink_context * ctx)920 zink_check_conditional_render(struct zink_context *ctx)
921 {
922    if (!ctx->render_condition_active)
923       return true;
924    assert(ctx->render_condition.query);
925 
926    union pipe_query_result result;
927    zink_get_query_result(&ctx->base, (struct pipe_query*)ctx->render_condition.query, true, &result);
928    return is_bool_query(ctx->render_condition.query) ?
929           ctx->render_condition.inverted != result.b :
930           ctx->render_condition.inverted != !!result.u64;
931 }
932 
933 static void
zink_render_condition(struct pipe_context * pctx,struct pipe_query * pquery,bool condition,enum pipe_render_cond_flag mode)934 zink_render_condition(struct pipe_context *pctx,
935                       struct pipe_query *pquery,
936                       bool condition,
937                       enum pipe_render_cond_flag mode)
938 {
939    struct zink_context *ctx = zink_context(pctx);
940    struct zink_query *query = (struct zink_query *)pquery;
941    zink_batch_no_rp(ctx);
942    VkQueryResultFlagBits flags = 0;
943 
944    if (query == NULL) {
945       /* force conditional clears if they exist */
946       if (ctx->clears_enabled && !ctx->batch.in_rp)
947          zink_batch_rp(ctx);
948       if (ctx->batch.in_rp)
949          zink_stop_conditional_render(ctx);
950       ctx->render_condition_active = false;
951       ctx->render_condition.query = NULL;
952       return;
953    }
954 
955    if (!query->predicate) {
956       struct pipe_resource *pres;
957 
958       /* need to create a vulkan buffer to copy the data into */
959       pres = pipe_buffer_create(pctx->screen, PIPE_BIND_QUERY_BUFFER, PIPE_USAGE_DEFAULT, sizeof(uint64_t));
960       if (!pres)
961          return;
962 
963       query->predicate = zink_resource(pres);
964    }
965    if (query->predicate_dirty) {
966       struct zink_resource *res = query->predicate;
967 
968       if (mode == PIPE_RENDER_COND_WAIT || mode == PIPE_RENDER_COND_BY_REGION_WAIT)
969          flags |= VK_QUERY_RESULT_WAIT_BIT;
970 
971       flags |= VK_QUERY_RESULT_64_BIT;
972       int num_results = query->curr_query - query->last_start;
973       if (query->type != PIPE_QUERY_PRIMITIVES_GENERATED &&
974           !is_so_overflow_query(query)) {
975          copy_results_to_buffer(ctx, query, res, 0, num_results, flags);
976       } else {
977          /* these need special handling */
978          force_cpu_read(ctx, pquery, PIPE_QUERY_TYPE_U32, &res->base.b, 0);
979       }
980       query->predicate_dirty = false;
981    }
982    ctx->render_condition.inverted = condition;
983    ctx->render_condition_active = true;
984    ctx->render_condition.query = query;
985    if (ctx->batch.in_rp)
986       zink_start_conditional_render(ctx);
987 }
988 
989 static void
zink_get_query_result_resource(struct pipe_context * pctx,struct pipe_query * pquery,bool wait,enum pipe_query_value_type result_type,int index,struct pipe_resource * pres,unsigned offset)990 zink_get_query_result_resource(struct pipe_context *pctx,
991                                struct pipe_query *pquery,
992                                bool wait,
993                                enum pipe_query_value_type result_type,
994                                int index,
995                                struct pipe_resource *pres,
996                                unsigned offset)
997 {
998    struct zink_context *ctx = zink_context(pctx);
999    struct zink_screen *screen = zink_screen(pctx->screen);
1000    struct zink_query *query = (struct zink_query*)pquery;
1001    struct zink_resource *res = zink_resource(pres);
1002    unsigned result_size = result_type <= PIPE_QUERY_TYPE_U32 ? sizeof(uint32_t) : sizeof(uint64_t);
1003    VkQueryResultFlagBits size_flags = result_type <= PIPE_QUERY_TYPE_U32 ? 0 : VK_QUERY_RESULT_64_BIT;
1004    unsigned num_queries = query->curr_query - query->last_start;
1005    unsigned query_id = query->last_start;
1006 
1007    if (index == -1) {
1008       /* VK_QUERY_RESULT_WITH_AVAILABILITY_BIT will ALWAYS write some kind of result data
1009        * in addition to the availability result, which is a problem if we're just trying to get availability data
1010        *
1011        * if we know that there's no valid buffer data in the preceding buffer range, then we can just
1012        * stomp on it with a glorious queued buffer copy instead of forcing a stall to manually write to the
1013        * buffer
1014        */
1015 
1016       VkQueryResultFlags flag = is_time_query(query) ? 0 : VK_QUERY_RESULT_PARTIAL_BIT;
1017       if (zink_batch_usage_check_completion(ctx, query->batch_id)) {
1018          uint64_t u64[2] = {0};
1019          if (VKCTX(GetQueryPoolResults)(screen->dev, query->query_pool, query_id, 1, 2 * result_size, u64,
1020                                    0, size_flags | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | flag) == VK_SUCCESS) {
1021             pipe_buffer_write(pctx, pres, offset, result_size, (unsigned char*)u64 + result_size);
1022             return;
1023          }
1024       }
1025       struct pipe_resource *staging = pipe_buffer_create(pctx->screen, 0, PIPE_USAGE_STAGING, result_size * 2);
1026       copy_results_to_buffer(ctx, query, zink_resource(staging), 0, 1, size_flags | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | flag);
1027       zink_copy_buffer(ctx, res, zink_resource(staging), offset, result_size, result_size);
1028       pipe_resource_reference(&staging, NULL);
1029       return;
1030    }
1031 
1032    if (!is_time_query(query) && !is_bool_query(query)) {
1033       if (num_queries == 1 && query->type != PIPE_QUERY_PRIMITIVES_GENERATED &&
1034                               query->type != PIPE_QUERY_PRIMITIVES_EMITTED &&
1035                               !is_bool_query(query)) {
1036          if (size_flags == VK_QUERY_RESULT_64_BIT) {
1037             if (query->needs_update)
1038                update_qbo(ctx, query);
1039             /* internal qbo always writes 64bit value so we can just direct copy */
1040             zink_copy_buffer(ctx, res, zink_resource(query->curr_qbo->buffer), offset,
1041                              get_buffer_offset(query, query->curr_qbo->buffer, query->last_start),
1042                              result_size);
1043          } else
1044             /* have to do a new copy for 32bit */
1045             copy_results_to_buffer(ctx, query, res, offset, 1, size_flags);
1046          return;
1047       }
1048    }
1049 
1050    /* TODO: use CS to aggregate results */
1051 
1052    /* unfortunately, there's no way to accumulate results from multiple queries on the gpu without either
1053     * clobbering all but the last result or writing the results sequentially, so we have to manually write the result
1054     */
1055    force_cpu_read(ctx, pquery, result_type, pres, offset);
1056 }
1057 
1058 static uint64_t
zink_get_timestamp(struct pipe_context * pctx)1059 zink_get_timestamp(struct pipe_context *pctx)
1060 {
1061    struct zink_screen *screen = zink_screen(pctx->screen);
1062    uint64_t timestamp, deviation;
1063    assert(screen->info.have_EXT_calibrated_timestamps);
1064    VkCalibratedTimestampInfoEXT cti = {0};
1065    cti.sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT;
1066    cti.timeDomain = VK_TIME_DOMAIN_DEVICE_EXT;
1067    VKSCR(GetCalibratedTimestampsEXT)(screen->dev, 1, &cti, &timestamp, &deviation);
1068    timestamp_to_nanoseconds(screen, &timestamp);
1069    return timestamp;
1070 }
1071 
1072 void
zink_context_query_init(struct pipe_context * pctx)1073 zink_context_query_init(struct pipe_context *pctx)
1074 {
1075    struct zink_context *ctx = zink_context(pctx);
1076    list_inithead(&ctx->suspended_queries);
1077    list_inithead(&ctx->primitives_generated_queries);
1078 
1079    pctx->create_query = zink_create_query;
1080    pctx->destroy_query = zink_destroy_query;
1081    pctx->begin_query = zink_begin_query;
1082    pctx->end_query = zink_end_query;
1083    pctx->get_query_result = zink_get_query_result;
1084    pctx->get_query_result_resource = zink_get_query_result_resource;
1085    pctx->set_active_query_state = zink_set_active_query_state;
1086    pctx->render_condition = zink_render_condition;
1087    pctx->get_timestamp = zink_get_timestamp;
1088 }
1089