mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 00:58:05 +02:00
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:
parent
d61d4df02e
commit
424a614ff1
3 changed files with 261 additions and 46 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue