+struct hud_batch_query_context {
+ unsigned num_query_types;
+ unsigned allocated_query_types;
+ unsigned *query_types;
+
+ boolean failed;
+ struct pipe_query *query[NUM_QUERIES];
+ union pipe_query_result *result[NUM_QUERIES];
+ unsigned head, pending, results;
+};
+
+void
+hud_batch_query_update(struct hud_batch_query_context *bq,
+ struct pipe_context *pipe)
+{
+ if (!bq || bq->failed)
+ return;
+
+ if (bq->query[bq->head])
+ pipe->end_query(pipe, bq->query[bq->head]);
+
+ bq->results = 0;
+
+ while (bq->pending) {
+ unsigned idx = (bq->head - bq->pending + 1) % NUM_QUERIES;
+ struct pipe_query *query = bq->query[idx];
+
+ if (!bq->result[idx])
+ bq->result[idx] = MALLOC(sizeof(bq->result[idx]->batch[0]) *
+ bq->num_query_types);
+ if (!bq->result[idx]) {
+ fprintf(stderr, "gallium_hud: out of memory.\n");
+ bq->failed = TRUE;
+ return;
+ }
+
+ if (!pipe->get_query_result(pipe, query, FALSE, bq->result[idx]))
+ break;
+
+ ++bq->results;
+ --bq->pending;
+ }
+
+ bq->head = (bq->head + 1) % NUM_QUERIES;
+
+ if (bq->pending == NUM_QUERIES) {
+ fprintf(stderr,
+ "gallium_hud: all queries busy after %i frames, dropping data.\n",
+ NUM_QUERIES);
+
+ assert(bq->query[bq->head]);
+
+ pipe->destroy_query(pipe, bq->query[bq->head]);
+ bq->query[bq->head] = NULL;
+ }
+
+ ++bq->pending;
+
+ if (!bq->query[bq->head]) {
+ bq->query[bq->head] = pipe->create_batch_query(pipe,
+ bq->num_query_types,
+ bq->query_types);
+
+ if (!bq->query[bq->head]) {
+ fprintf(stderr,
+ "gallium_hud: create_batch_query failed. You may have "
+ "selected too many or incompatible queries.\n");
+ bq->failed = TRUE;
+ return;
+ }
+ }
+}
+
+void
+hud_batch_query_begin(struct hud_batch_query_context *bq,
+ struct pipe_context *pipe)
+{
+ if (!bq || bq->failed || !bq->query[bq->head])
+ return;
+
+ if (!pipe->begin_query(pipe, bq->query[bq->head])) {
+ fprintf(stderr,
+ "gallium_hud: could not begin batch query. You may have "
+ "selected too many or incompatible queries.\n");
+ bq->failed = TRUE;
+ }
+}
+
+static boolean
+batch_query_add(struct hud_batch_query_context **pbq,
+ unsigned query_type, unsigned *result_index)
+{
+ struct hud_batch_query_context *bq = *pbq;
+ unsigned i;
+
+ if (!bq) {
+ bq = CALLOC_STRUCT(hud_batch_query_context);
+ if (!bq)
+ return false;
+ *pbq = bq;
+ }
+
+ for (i = 0; i < bq->num_query_types; ++i) {
+ if (bq->query_types[i] == query_type) {
+ *result_index = i;
+ return true;
+ }
+ }
+
+ if (bq->num_query_types == bq->allocated_query_types) {
+ unsigned new_alloc = MAX2(16, bq->allocated_query_types * 2);
+ unsigned *new_query_types
+ = REALLOC(bq->query_types,
+ bq->allocated_query_types * sizeof(unsigned),
+ new_alloc * sizeof(unsigned));
+ if (!new_query_types)
+ return false;
+ bq->query_types = new_query_types;
+ bq->allocated_query_types = new_alloc;
+ }
+
+ bq->query_types[bq->num_query_types] = query_type;
+ *result_index = bq->num_query_types++;
+ return true;
+}
+
+void
+hud_batch_query_cleanup(struct hud_batch_query_context **pbq,
+ struct pipe_context *pipe)
+{
+ struct hud_batch_query_context *bq = *pbq;
+ unsigned idx;
+
+ if (!bq)
+ return;
+
+ *pbq = NULL;
+
+ if (bq->query[bq->head] && !bq->failed)
+ pipe->end_query(pipe, bq->query[bq->head]);
+
+ for (idx = 0; idx < NUM_QUERIES; ++idx) {
+ if (bq->query[idx])
+ pipe->destroy_query(pipe, bq->query[idx]);
+ FREE(bq->result[idx]);
+ }
+
+ FREE(bq->query_types);
+ FREE(bq);
+}
+