gallium/hud: add support for batch queries

v2 + v3: be more defensive about allocations

Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Tested-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
This commit is contained in:
Nicolai Hähnle 2015-11-10 17:04:32 +01:00
parent d61d4df02e
commit 424a614ff1
3 changed files with 261 additions and 46 deletions

View file

@ -60,6 +60,7 @@ struct hud_context {
struct cso_context *cso;
struct u_upload_mgr *uploader;
struct hud_batch_query_context *batch_query;
struct list_head pane_list;
/* states */
@ -523,6 +524,8 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex)
hud_alloc_vertices(hud, &hud->text, 4 * 512, 4 * sizeof(float));
/* prepare all graphs */
hud_batch_query_update(hud->batch_query);
LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
gr->query_new_value(gr);
@ -916,17 +919,21 @@ hud_parse_env_var(struct hud_context *hud, const char *env)
}
else if (strcmp(name, "samples-passed") == 0 &&
has_occlusion_query(hud->pipe->screen)) {
hud_pipe_query_install(pane, hud->pipe, "samples-passed",
hud_pipe_query_install(&hud->batch_query, pane, hud->pipe,
"samples-passed",
PIPE_QUERY_OCCLUSION_COUNTER, 0, 0,
PIPE_DRIVER_QUERY_TYPE_UINT64,
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE);
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
0);
}
else if (strcmp(name, "primitives-generated") == 0 &&
has_streamout(hud->pipe->screen)) {
hud_pipe_query_install(pane, hud->pipe, "primitives-generated",
hud_pipe_query_install(&hud->batch_query, pane, hud->pipe,
"primitives-generated",
PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0,
PIPE_DRIVER_QUERY_TYPE_UINT64,
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE);
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
0);
}
else {
boolean processed = FALSE;
@ -951,17 +958,19 @@ hud_parse_env_var(struct hud_context *hud, const char *env)
if (strcmp(name, pipeline_statistics_names[i]) == 0)
break;
if (i < Elements(pipeline_statistics_names)) {
hud_pipe_query_install(pane, hud->pipe, name,
hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, name,
PIPE_QUERY_PIPELINE_STATISTICS, i,
0, PIPE_DRIVER_QUERY_TYPE_UINT64,
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE);
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
0);
processed = TRUE;
}
}
/* driver queries */
if (!processed) {
if (!hud_driver_query_install(pane, hud->pipe, name)){
if (!hud_driver_query_install(&hud->batch_query, pane, hud->pipe,
name)) {
fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name);
}
}
@ -1322,6 +1331,7 @@ hud_destroy(struct hud_context *hud)
FREE(pane);
}
hud_batch_query_cleanup(&hud->batch_query);
pipe->delete_fs_state(pipe, hud->fs_color);
pipe->delete_fs_state(pipe, hud->fs_text);
pipe->delete_vs_state(pipe, hud->vs);

View file

@ -34,13 +34,164 @@
#include "hud/hud_private.h"
#include "pipe/p_screen.h"
#include "os/os_time.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include <stdio.h>
// Must be a power of two
#define NUM_QUERIES 8
struct hud_batch_query_context {
struct pipe_context *pipe;
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;
pipe = bq->pipe;
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(bq->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;
}
}
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,
struct pipe_context *pipe, 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;
bq->pipe = pipe;
*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 hud_batch_query_context *bq = *pbq;
unsigned idx;
if (!bq)
return;
*pbq = NULL;
if (bq->query[bq->head] && !bq->failed)
bq->pipe->end_query(bq->pipe, bq->query[bq->head]);
for (idx = 0; idx < NUM_QUERIES; ++idx) {
if (bq->query[idx])
bq->pipe->destroy_query(bq->pipe, bq->query[idx]);
FREE(bq->result[idx]);
}
FREE(bq->query_types);
FREE(bq);
}
struct query_info {
struct pipe_context *pipe;
struct hud_batch_query_context *batch;
unsigned query_type;
unsigned result_index; /* unit depends on query_type */
enum pipe_driver_query_result_type result_type;
@ -55,11 +206,26 @@ struct query_info {
};
static void
query_new_value(struct hud_graph *gr)
query_new_value_batch(struct query_info *info)
{
struct hud_batch_query_context *bq = info->batch;
unsigned result_index = info->result_index;
unsigned idx = (bq->head - bq->pending) % NUM_QUERIES;
unsigned results = bq->results;
while (results) {
info->results_cumulative += bq->result[idx]->batch[result_index].u64;
++info->num_results;
--results;
idx = (idx - 1) % NUM_QUERIES;
}
}
static void
query_new_value_normal(struct query_info *info)
{
struct query_info *info = gr->query_data;
struct pipe_context *pipe = info->pipe;
uint64_t now = os_time_get();
if (info->last_time) {
if (info->query[info->head])
@ -106,30 +272,9 @@ query_new_value(struct hud_graph *gr)
break;
}
}
if (info->num_results && info->last_time + gr->pane->period <= now) {
uint64_t value;
switch (info->result_type) {
default:
case PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE:
value = info->results_cumulative / info->num_results;
break;
case PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE:
value = info->results_cumulative;
break;
}
hud_graph_add_value(gr, value);
info->last_time = now;
info->results_cumulative = 0;
info->num_results = 0;
}
}
else {
/* initialize */
info->last_time = now;
info->query[info->head] = pipe->create_query(pipe, info->query_type, 0);
}
@ -137,12 +282,50 @@ query_new_value(struct hud_graph *gr)
pipe->begin_query(pipe, info->query[info->head]);
}
static void
query_new_value(struct hud_graph *gr)
{
struct query_info *info = gr->query_data;
uint64_t now = os_time_get();
if (info->batch) {
query_new_value_batch(info);
} else {
query_new_value_normal(info);
}
if (!info->last_time) {
info->last_time = now;
return;
}
if (info->num_results && info->last_time + gr->pane->period <= now) {
uint64_t value;
switch (info->result_type) {
default:
case PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE:
value = info->results_cumulative / info->num_results;
break;
case PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE:
value = info->results_cumulative;
break;
}
hud_graph_add_value(gr, value);
info->last_time = now;
info->results_cumulative = 0;
info->num_results = 0;
}
}
static void
free_query_info(void *ptr)
{
struct query_info *info = ptr;
if (info->last_time) {
if (!info->batch && info->last_time) {
struct pipe_context *pipe = info->pipe;
int i;
@ -158,11 +341,13 @@ free_query_info(void *ptr)
}
void
hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
hud_pipe_query_install(struct hud_batch_query_context **pbq,
struct hud_pane *pane, struct pipe_context *pipe,
const char *name, unsigned query_type,
unsigned result_index,
uint64_t max_value, enum pipe_driver_query_type type,
enum pipe_driver_query_result_type result_type)
enum pipe_driver_query_result_type result_type,
unsigned flags)
{
struct hud_graph *gr;
struct query_info *info;
@ -174,28 +359,40 @@ hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
strncpy(gr->name, name, sizeof(gr->name));
gr->name[sizeof(gr->name) - 1] = '\0';
gr->query_data = CALLOC_STRUCT(query_info);
if (!gr->query_data) {
FREE(gr);
return;
}
if (!gr->query_data)
goto fail_gr;
gr->query_new_value = query_new_value;
gr->free_query_data = free_query_info;
info = gr->query_data;
info->pipe = pipe;
info->query_type = query_type;
info->result_index = result_index;
info->result_type = result_type;
if (flags & PIPE_DRIVER_QUERY_FLAG_BATCH) {
if (!batch_query_add(pbq, pipe, query_type, &info->result_index))
goto fail_info;
info->batch = *pbq;
} else {
info->query_type = query_type;
info->result_index = result_index;
}
hud_pane_add_graph(pane, gr);
if (pane->max_value < max_value)
hud_pane_set_max_value(pane, max_value);
pane->type = type;
return;
fail_info:
FREE(info);
fail_gr:
FREE(gr);
}
boolean
hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe,
hud_driver_query_install(struct hud_batch_query_context **pbq,
struct hud_pane *pane, struct pipe_context *pipe,
const char *name)
{
struct pipe_screen *screen = pipe->screen;
@ -219,8 +416,9 @@ hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe,
if (!found)
return FALSE;
hud_pipe_query_install(pane, pipe, query.name, query.query_type, 0,
query.max_value.u64, query.type, query.result_type);
hud_pipe_query_install(pbq, pane, pipe, query.name, query.query_type, 0,
query.max_value.u64, query.type, query.result_type,
query.flags);
return TRUE;
}

View file

@ -80,19 +80,26 @@ void hud_pane_set_max_value(struct hud_pane *pane, uint64_t value);
void hud_graph_add_value(struct hud_graph *gr, uint64_t value);
/* graphs/queries */
struct hud_batch_query_context;
#define ALL_CPUS ~0 /* optionally set as cpu_index */
int hud_get_num_cpus(void);
void hud_fps_graph_install(struct hud_pane *pane);
void hud_cpu_graph_install(struct hud_pane *pane, unsigned cpu_index);
void hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
void hud_pipe_query_install(struct hud_batch_query_context **pbq,
struct hud_pane *pane, struct pipe_context *pipe,
const char *name, unsigned query_type,
unsigned result_index,
uint64_t max_value,
enum pipe_driver_query_type type,
enum pipe_driver_query_result_type result_type);
boolean hud_driver_query_install(struct hud_pane *pane,
enum pipe_driver_query_result_type result_type,
unsigned flags);
boolean hud_driver_query_install(struct hud_batch_query_context **pbq,
struct hud_pane *pane,
struct pipe_context *pipe, const char *name);
void hud_batch_query_update(struct hud_batch_query_context *bq);
void hud_batch_query_cleanup(struct hud_batch_query_context **pbq);
#endif