X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fhud%2Fhud_context.c;h=0cd3307a1a5f7cd01d25ddd9e98fdc85bf508198;hb=8c9b9aac7d09e65195dca6681d59c10e4ef713d9;hp=7fa62a91866b2b0ec45dfaa05e081932988935ab;hpb=431742dbba46b66e61a22f7186ec82a818685a31;p=mesa.git diff --git a/src/gallium/auxiliary/hud/hud_context.c b/src/gallium/auxiliary/hud/hud_context.c index 7fa62a91866..0cd3307a1a5 100644 --- a/src/gallium/auxiliary/hud/hud_context.c +++ b/src/gallium/auxiliary/hud/hud_context.c @@ -27,7 +27,7 @@ /* This head-up display module can draw transparent graphs on top of what * the app is rendering, visualizing various data like framerate, cpu load, - * performance counters, etc. It can be hook up into any state tracker. + * performance counters, etc. It can be hook up into any gallium frontend. * * The HUD is controlled with the GALLIUM_HUD environment variable. * Set GALLIUM_HUD=help for more info. @@ -39,11 +39,10 @@ #include "hud/hud_context.h" #include "hud/hud_private.h" -#include "hud/font.h" #include "cso_cache/cso_context.h" #include "util/u_draw_quad.h" -#include "util/u_format.h" +#include "util/format/u_format.h" #include "util/u_inlines.h" #include "util/u_memory.h" #include "util/u_math.h" @@ -56,52 +55,8 @@ /* Control the visibility of all HUD contexts */ static boolean huds_visible = TRUE; +static int hud_scale = 1; -struct hud_context { - struct pipe_context *pipe; - struct cso_context *cso; - struct u_upload_mgr *uploader; - - struct hud_batch_query_context *batch_query; - struct list_head pane_list; - - /* states */ - struct pipe_blend_state no_blend, alpha_blend; - struct pipe_depth_stencil_alpha_state dsa; - void *fs_color, *fs_text; - struct pipe_rasterizer_state rasterizer, rasterizer_aa_lines; - void *vs; - struct pipe_vertex_element velems[2]; - - /* font */ - struct util_font font; - struct pipe_sampler_view *font_sampler_view; - struct pipe_sampler_state font_sampler_state; - - /* VS constant buffer */ - struct { - float color[4]; - float two_div_fb_width; - float two_div_fb_height; - float translate[2]; - float scale[2]; - float padding[2]; - } constants; - struct pipe_constant_buffer constbuf; - - unsigned fb_width, fb_height; - - /* vertices for text and background drawing are accumulated here and then - * drawn all at once */ - struct vertex_queue { - float *vertices; - struct pipe_vertex_buffer vbuf; - unsigned max_num_vertices; - unsigned num_vertices; - } text, bg, whitelines; - - bool has_srgb; -}; #ifdef PIPE_OS_UNIX static void @@ -118,25 +73,31 @@ hud_draw_colored_prims(struct hud_context *hud, unsigned prim, int xoffset, int yoffset, float yscale) { struct cso_context *cso = hud->cso; - struct pipe_vertex_buffer vbuffer = {0}; + unsigned size = num_vertices * hud->color_prims.vbuf.stride; + + /* If a recording context is inactive, don't draw anything. */ + if (size > hud->color_prims.buffer_size) + return; + + memcpy(hud->color_prims.vertices, buffer, size); hud->constants.color[0] = r; hud->constants.color[1] = g; hud->constants.color[2] = b; hud->constants.color[3] = a; - hud->constants.translate[0] = (float) xoffset; - hud->constants.translate[1] = (float) yoffset; - hud->constants.scale[0] = 1; - hud->constants.scale[1] = yscale; + hud->constants.translate[0] = (float) (xoffset * hud_scale); + hud->constants.translate[1] = (float) (yoffset * hud_scale); + hud->constants.scale[0] = hud_scale; + hud->constants.scale[1] = yscale * hud_scale; cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); - vbuffer.user_buffer = buffer; - vbuffer.stride = 2 * sizeof(float); - - cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), - 1, &vbuffer); + cso_set_vertex_buffers(cso, 0, 1, &hud->color_prims.vbuf); cso_set_fragment_shader_handle(hud->cso, hud->fs_color); cso_draw_arrays(cso, prim, 0, num_vertices); + + hud->color_prims.vertices += size / sizeof(float); + hud->color_prims.vbuf.buffer_offset += size; + hud->color_prims.buffer_size -= size; } static void @@ -189,7 +150,7 @@ hud_draw_string(struct hud_context *hud, unsigned x, unsigned y, va_list ap; va_start(ap, str); - util_vsnprintf(buf, sizeof(buf), str, ap); + vsnprintf(buf, sizeof(buf), str, ap); va_end(ap); if (!*s) @@ -246,7 +207,7 @@ hud_draw_string(struct hud_context *hud, unsigned x, unsigned y, } static void -number_to_human_readable(uint64_t num, enum pipe_driver_query_type type, +number_to_human_readable(double num, enum pipe_driver_query_type type, char *out) { static const char *byte_units[] = @@ -263,6 +224,7 @@ number_to_human_readable(uint64_t num, enum pipe_driver_query_type type, static const char *volt_units[] = {" mV", " V"}; static const char *amp_units[] = {" mA", " A"}; static const char *watt_units[] = {" mW", " W"}; + static const char *float_units[] = {""}; const char **units; unsigned max_unit; @@ -291,6 +253,10 @@ number_to_human_readable(uint64_t num, enum pipe_driver_query_type type, max_unit = ARRAY_SIZE(temperature_units)-1; units = temperature_units; break; + case PIPE_DRIVER_QUERY_TYPE_FLOAT: + max_unit = ARRAY_SIZE(float_units)-1; + units = float_units; + break; case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE: max_unit = ARRAY_SIZE(percent_units)-1; units = percent_units; @@ -432,6 +398,26 @@ hud_pane_accumulate_vertices(struct hud_context *hud, hud->whitelines.num_vertices += num/2; } +static void +hud_pane_accumulate_vertices_simple(struct hud_context *hud, + const struct hud_pane *pane) +{ + struct hud_graph *gr; + unsigned i; + char str[32]; + + /* draw info below the pane */ + i = 0; + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + unsigned x = pane->x1; + unsigned y = pane->y_simple + i*hud->font.glyph_height; + + number_to_human_readable(gr->current_value, pane->type, str); + hud_draw_string(hud, x, y, "%s: %s", gr->name, str); + i++; + } +} + static void hud_pane_draw_colored_objects(struct hud_context *hud, const struct hud_pane *pane) @@ -457,23 +443,21 @@ hud_pane_draw_colored_objects(struct hud_context *hud, } static void -hud_alloc_vertices(struct hud_context *hud, struct vertex_queue *v, - unsigned num_vertices, unsigned stride) +hud_prepare_vertices(struct hud_context *hud, struct vertex_queue *v, + unsigned num_vertices, unsigned stride) { v->num_vertices = 0; v->max_num_vertices = num_vertices; v->vbuf.stride = stride; - u_upload_alloc(hud->uploader, 0, v->vbuf.stride * v->max_num_vertices, - 16, &v->vbuf.buffer_offset, &v->vbuf.buffer, - (void**)&v->vertices); + v->buffer_size = stride * num_vertices; } /** * Draw the HUD to the texture \p tex. * The texture is usually the back buffer being displayed. */ -void -hud_draw(struct hud_context *hud, struct pipe_resource *tex) +static void +hud_draw_results(struct hud_context *hud, struct pipe_resource *tex) { struct cso_context *cso = hud->cso; struct pipe_context *pipe = hud->pipe; @@ -483,7 +467,6 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) const struct pipe_sampler_state *sampler_states[] = { &hud->font_sampler_state }; struct hud_pane *pane; - struct hud_graph *gr, *next; if (!huds_visible) return; @@ -556,49 +539,13 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) cso_set_tesseval_shader_handle(cso, NULL); cso_set_geometry_shader_handle(cso, NULL); cso_set_vertex_shader_handle(cso, hud->vs); - cso_set_vertex_elements(cso, 2, hud->velems); + cso_set_vertex_elements(cso, &hud->velems); cso_set_render_condition(cso, NULL, FALSE, 0); cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1, &hud->font_sampler_view); cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states); cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); - /* prepare vertex buffers */ - hud_alloc_vertices(hud, &hud->bg, 4 * 256, 2 * sizeof(float)); - hud_alloc_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float)); - hud_alloc_vertices(hud, &hud->text, 16 * 1024, 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); - } - - if (pane->sort_items) { - LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) { - /* ignore the last one */ - if (&gr->head == pane->graph_list.prev) - continue; - - /* This is an incremental bubble sort, because we only do one pass - * per frame. It will eventually reach an equilibrium. - */ - if (gr->current_value < - LIST_ENTRY(struct hud_graph, next, head)->current_value) { - LIST_DEL(&gr->head); - LIST_ADD(&gr->head, &next->head); - } - } - } - - hud_pane_accumulate_vertices(hud, pane); - } - - /* unmap the uploader's vertex buffer before drawing */ - u_upload_unmap(hud->uploader); - /* draw accumulated vertices for background quads */ cso_set_blend(cso, &hud->alpha_blend); cso_set_fragment_shader_handle(hud->cso, hud->fs_color); @@ -610,15 +557,31 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) hud->constants.color[3] = 0.666f; hud->constants.translate[0] = 0; hud->constants.translate[1] = 0; - hud->constants.scale[0] = 1; - hud->constants.scale[1] = 1; + hud->constants.scale[0] = hud_scale; + hud->constants.scale[1] = hud_scale; cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); - cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1, - &hud->bg.vbuf); + + cso_set_vertex_buffers(cso, 0, 1, &hud->bg.vbuf); cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices); } - pipe_resource_reference(&hud->bg.vbuf.buffer, NULL); + pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL); + + /* draw accumulated vertices for text */ + if (hud->text.num_vertices) { + cso_set_vertex_buffers(cso, 0, 1, &hud->text.vbuf); + cso_set_fragment_shader_handle(hud->cso, hud->fs_text); + cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices); + } + pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL); + + if (hud->simple) { + cso_restore_state(cso); + cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); + + pipe_surface_reference(&surf, NULL); + return; + } /* draw accumulated vertices for white lines */ cso_set_blend(cso, &hud->no_blend); @@ -629,29 +592,19 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) hud->constants.color[3] = 1; hud->constants.translate[0] = 0; hud->constants.translate[1] = 0; - hud->constants.scale[0] = 1; - hud->constants.scale[1] = 1; + hud->constants.scale[0] = hud_scale; + hud->constants.scale[1] = hud_scale; cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); if (hud->whitelines.num_vertices) { - cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1, - &hud->whitelines.vbuf); + cso_set_vertex_buffers(cso, 0, 1, &hud->whitelines.vbuf); cso_set_fragment_shader_handle(hud->cso, hud->fs_color); cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices); } - pipe_resource_reference(&hud->whitelines.vbuf.buffer, NULL); - - /* draw accumulated vertices for text */ - cso_set_blend(cso, &hud->alpha_blend); - if (hud->text.num_vertices) { - cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1, - &hud->text.vbuf); - cso_set_fragment_shader_handle(hud->cso, hud->fs_text); - cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices); - } - pipe_resource_reference(&hud->text.vbuf.buffer, NULL); + pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL); /* draw the rest */ + cso_set_blend(cso, &hud->alpha_blend); cso_set_rasterizer(cso, &hud->rasterizer_aa_lines); LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { if (pane) @@ -664,6 +617,145 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) pipe_surface_reference(&surf, NULL); } +static void +hud_start_queries(struct hud_context *hud, struct pipe_context *pipe) +{ + struct hud_pane *pane; + struct hud_graph *gr; + + /* Start queries. */ + hud_batch_query_begin(hud->batch_query, pipe); + + LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + if (gr->begin_query) + gr->begin_query(gr, pipe); + } + } +} + +/* Stop queries, query results, and record vertices for charts. */ +static void +hud_stop_queries(struct hud_context *hud, struct pipe_context *pipe) +{ + struct hud_pane *pane; + struct hud_graph *gr, *next; + + /* prepare vertex buffers */ + hud_prepare_vertices(hud, &hud->bg, 16 * 256, 2 * sizeof(float)); + hud_prepare_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float)); + hud_prepare_vertices(hud, &hud->text, 16 * 1024, 4 * sizeof(float)); + hud_prepare_vertices(hud, &hud->color_prims, 32 * 1024, 2 * sizeof(float)); + + /* Allocate everything once and divide the storage into 3 portions + * manually, because u_upload_alloc can unmap memory from previous calls. + */ + u_upload_alloc(pipe->stream_uploader, 0, + hud->bg.buffer_size + + hud->whitelines.buffer_size + + hud->text.buffer_size + + hud->color_prims.buffer_size, + 16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource, + (void**)&hud->bg.vertices); + if (!hud->bg.vertices) + return; + + pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); + pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); + pipe_resource_reference(&hud->color_prims.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); + + hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset + + hud->bg.buffer_size; + hud->whitelines.vertices = hud->bg.vertices + + hud->bg.buffer_size / sizeof(float); + + hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset + + hud->whitelines.buffer_size; + hud->text.vertices = hud->whitelines.vertices + + hud->whitelines.buffer_size / sizeof(float); + + hud->color_prims.vbuf.buffer_offset = hud->text.vbuf.buffer_offset + + hud->text.buffer_size; + hud->color_prims.vertices = hud->text.vertices + + hud->text.buffer_size / sizeof(float); + + /* prepare all graphs */ + hud_batch_query_update(hud->batch_query, pipe); + + LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + gr->query_new_value(gr, pipe); + } + + if (pane->sort_items) { + LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) { + /* ignore the last one */ + if (&gr->head == pane->graph_list.prev) + continue; + + /* This is an incremental bubble sort, because we only do one pass + * per frame. It will eventually reach an equilibrium. + */ + if (gr->current_value < + LIST_ENTRY(struct hud_graph, next, head)->current_value) { + list_del(&gr->head); + list_add(&gr->head, &next->head); + } + } + } + + if (hud->simple) + hud_pane_accumulate_vertices_simple(hud, pane); + else + hud_pane_accumulate_vertices(hud, pane); + } + + /* unmap the uploader's vertex buffer before drawing */ + u_upload_unmap(pipe->stream_uploader); +} + +/** + * Record queries and draw the HUD. The "cso" parameter acts as a filter. + * If "cso" is not the recording context, recording is skipped. + * If "cso" is not the drawing context, drawing is skipped. + * cso == NULL ignores the filter. + */ +void +hud_run(struct hud_context *hud, struct cso_context *cso, + struct pipe_resource *tex) +{ + struct pipe_context *pipe = cso ? cso_get_pipe_context(cso) : NULL; + + /* If "cso" is the recording or drawing context or NULL, execute + * the operation. Otherwise, don't do anything. + */ + if (hud->record_pipe && (!pipe || pipe == hud->record_pipe)) + hud_stop_queries(hud, hud->record_pipe); + + if (hud->cso && (!cso || cso == hud->cso)) + hud_draw_results(hud, tex); + + if (hud->record_pipe && (!pipe || pipe == hud->record_pipe)) + hud_start_queries(hud, hud->record_pipe); +} + +/** + * Record query results and assemble vertices if "pipe" is a recording but + * not drawing context. + */ +void +hud_record_only(struct hud_context *hud, struct pipe_context *pipe) +{ + assert(pipe); + + /* If it's a drawing context, only hud_run() records query results. */ + if (pipe == hud->pipe || pipe != hud->record_pipe) + return; + + hud_stop_queries(hud, hud->record_pipe); + hud_start_queries(hud, hud->record_pipe); +} + static void fixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10) { @@ -689,9 +781,10 @@ hud_pane_set_max_value(struct hud_pane *pane, uint64_t value) * hard-to-read numbers like 1.753. */ - /* Find the left-most digit. */ + /* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't + * overflow. (11 is safe) */ exp10 = 1; - for (i = 0; value > 9 * exp10; i++) { + for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) { exp10 *= 10; fixup_bytes(pane->type, i + 1, &exp10); } @@ -776,7 +869,9 @@ hud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane) } static struct hud_pane * -hud_pane_create(unsigned x1, unsigned y1, unsigned x2, unsigned y2, +hud_pane_create(struct hud_context *hud, + unsigned x1, unsigned y1, unsigned x2, unsigned y2, + unsigned y_simple, unsigned period, uint64_t max_value, uint64_t ceiling, boolean dyn_ceiling, boolean sort_items) { @@ -785,10 +880,12 @@ hud_pane_create(unsigned x1, unsigned y1, unsigned x2, unsigned y2, if (!pane) return NULL; + pane->hud = hud; pane->x1 = x1; pane->y1 = y1; pane->x2 = x2; pane->y2 = y2; + pane->y_simple = y_simple; pane->inner_x1 = x1 + 1; pane->inner_x2 = x2 - 1; pane->inner_y1 = y1 + 1; @@ -803,7 +900,7 @@ hud_pane_create(unsigned x1, unsigned y1, unsigned x2, unsigned y2, pane->sort_items = sort_items; pane->initial_max_value = max_value; hud_pane_set_max_value(pane, max_value); - LIST_INITHEAD(&pane->graph_list); + list_inithead(&pane->graph_list); return pane; } @@ -851,19 +948,25 @@ hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr) gr->color[1] = colors[color][1]; gr->color[2] = colors[color][2]; gr->pane = pane; - LIST_ADDTAIL(&gr->head, &pane->graph_list); + list_addtail(&gr->head, &pane->graph_list); pane->num_graphs++; pane->next_color++; } void -hud_graph_add_value(struct hud_graph *gr, uint64_t value) +hud_graph_add_value(struct hud_graph *gr, double value) { gr->current_value = value; value = value > gr->pane->ceiling ? gr->pane->ceiling : value; - if (gr->fd) - fprintf(gr->fd, "%" PRIu64 "\n", value); + if (gr->fd) { + if (fabs(value - lround(value)) > FLT_EPSILON) { + fprintf(gr->fd, "%f\n", value); + } + else { + fprintf(gr->fd, "%" PRIu64 "\n", (uint64_t) lround(value)); + } + } if (gr->index == gr->pane->max_num_vertices) { gr->vertices[0] = 0; @@ -887,34 +990,73 @@ hud_graph_add_value(struct hud_graph *gr, uint64_t value) } static void -hud_graph_destroy(struct hud_graph *graph) +hud_graph_destroy(struct hud_graph *graph, struct pipe_context *pipe) { FREE(graph->vertices); if (graph->free_query_data) - graph->free_query_data(graph->query_data); + graph->free_query_data(graph->query_data, pipe); if (graph->fd) fclose(graph->fd); FREE(graph); } -void +static void strcat_without_spaces(char *dst, const char *src) +{ + dst += strlen(dst); + while (*src) { + if (*src == ' ') + *dst++ = '_'; + else + *dst++ = *src; + src++; + } + *dst = 0; +} + + +#ifdef PIPE_OS_WINDOWS +#define W_OK 0 +static int +access(const char *pathname, int mode) +{ + /* no-op */ + return 0; +} + +#define PATH_SEP "\\" + +#else + +#define PATH_SEP "/" + +#endif + + +/** + * If the GALLIUM_HUD_DUMP_DIR env var is set, we'll write the raw + * HUD values to files at ${GALLIUM_HUD_DUMP_DIR}/ where + * is a HUD variable such as "fps", or "cpu" + */ +static void hud_graph_set_dump_file(struct hud_graph *gr) { -#ifndef PIPE_OS_WINDOWS const char *hud_dump_dir = getenv("GALLIUM_HUD_DUMP_DIR"); - char *dump_file; if (hud_dump_dir && access(hud_dump_dir, W_OK) == 0) { - dump_file = malloc(strlen(hud_dump_dir) + sizeof("/") + sizeof(gr->name)); + char *dump_file = malloc(strlen(hud_dump_dir) + sizeof(PATH_SEP) + + sizeof(gr->name)); if (dump_file) { strcpy(dump_file, hud_dump_dir); - strcat(dump_file, "/"); - strcat(dump_file, gr->name); + strcat(dump_file, PATH_SEP); + strcat_without_spaces(dump_file, gr->name); gr->fd = fopen(dump_file, "w+"); + if (gr->fd) { + /* flush output after each line is written */ + setvbuf(gr->fd, NULL, _IOLBF, 0); + } free(dump_file); } } -#endif } /** @@ -1038,13 +1180,14 @@ has_pipeline_stats_query(struct pipe_screen *screen) } static void -hud_parse_env_var(struct hud_context *hud, const char *env) +hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen, + const char *env) { unsigned num, i; char name_a[256], s[256]; char *name; struct hud_pane *pane = NULL; - unsigned x = 10, y = 10; + unsigned x = 10, y = 10, y_simple = 10; unsigned width = 251, height = 100; unsigned period = 500 * 1000; /* default period (1/2 second) */ uint64_t ceiling = UINT64_MAX; @@ -1054,6 +1197,11 @@ hud_parse_env_var(struct hud_context *hud, const char *env) boolean sort_items = false; const char *period_env; + if (strncmp(env, "simple,", 7) == 0) { + hud->simple = true; + env += 7; + } + /* * The GALLIUM_HUD_PERIOD env var sets the graph update rate. * The env var is in seconds (a float). @@ -1068,6 +1216,8 @@ hud_parse_env_var(struct hud_context *hud, const char *env) } while ((num = parse_string(env, name_a)) != 0) { + bool added = true; + env += num; /* check for explicit location, size and etc. settings */ @@ -1082,8 +1232,8 @@ hud_parse_env_var(struct hud_context *hud, const char *env) column_width = width > column_width ? width : column_width; if (!pane) { - pane = hud_pane_create(x, y, x + width, y + height, period, 10, - ceiling, dyn_ceiling, sort_items); + pane = hud_pane_create(hud, x, y, x + width, y + height, y_simple, + period, 10, ceiling, dyn_ceiling, sort_items); if (!pane) return; } @@ -1094,20 +1244,38 @@ hud_parse_env_var(struct hud_context *hud, const char *env) } /* Add a graph. */ -#if HAVE_GALLIUM_EXTRA_HUD || HAVE_LIBSENSORS +#if defined(HAVE_GALLIUM_EXTRA_HUD) || defined(HAVE_LIBSENSORS) char arg_name[64]; #endif /* IF YOU CHANGE THIS, UPDATE print_help! */ if (strcmp(name, "fps") == 0) { hud_fps_graph_install(pane); } + else if (strcmp(name, "frametime") == 0) { + hud_frametime_graph_install(pane); + } else if (strcmp(name, "cpu") == 0) { hud_cpu_graph_install(pane, ALL_CPUS); } else if (sscanf(name, "cpu%u%s", &i, s) == 1) { hud_cpu_graph_install(pane, i); } -#if HAVE_GALLIUM_EXTRA_HUD + else if (strcmp(name, "API-thread-busy") == 0) { + hud_thread_busy_install(pane, name, false); + } + else if (strcmp(name, "API-thread-offloaded-slots") == 0) { + hud_thread_counter_install(pane, name, HUD_COUNTER_OFFLOADED); + } + else if (strcmp(name, "API-thread-direct-slots") == 0) { + hud_thread_counter_install(pane, name, HUD_COUNTER_DIRECT); + } + else if (strcmp(name, "API-thread-num-syncs") == 0) { + hud_thread_counter_install(pane, name, HUD_COUNTER_SYNCS); + } + else if (strcmp(name, "main-thread-busy") == 0) { + hud_thread_busy_install(pane, name, true); + } +#ifdef HAVE_GALLIUM_EXTRA_HUD else if (sscanf(name, "nic-rx-%s", arg_name) == 1) { hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX); } @@ -1139,7 +1307,7 @@ hud_parse_env_var(struct hud_context *hud, const char *env) pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; } #endif -#if HAVE_LIBSENSORS +#ifdef HAVE_LIBSENSORS else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) { hud_sensors_temp_graph_install(pane, arg_name, SENSORS_TEMP_CURRENT); @@ -1167,8 +1335,8 @@ hud_parse_env_var(struct hud_context *hud, const char *env) } #endif else if (strcmp(name, "samples-passed") == 0 && - has_occlusion_query(hud->pipe->screen)) { - hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, + has_occlusion_query(screen)) { + hud_pipe_query_install(&hud->batch_query, pane, "samples-passed", PIPE_QUERY_OCCLUSION_COUNTER, 0, 0, PIPE_DRIVER_QUERY_TYPE_UINT64, @@ -1176,8 +1344,8 @@ hud_parse_env_var(struct hud_context *hud, const char *env) 0); } else if (strcmp(name, "primitives-generated") == 0 && - has_streamout(hud->pipe->screen)) { - hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, + has_streamout(screen)) { + hud_pipe_query_install(&hud->batch_query, pane, "primitives-generated", PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0, PIPE_DRIVER_QUERY_TYPE_UINT64, @@ -1188,7 +1356,7 @@ hud_parse_env_var(struct hud_context *hud, const char *env) boolean processed = FALSE; /* pipeline statistics queries */ - if (has_pipeline_stats_query(hud->pipe->screen)) { + if (has_pipeline_stats_query(screen)) { static const char *pipeline_statistics_names[] = { "ia-vertices", @@ -1207,7 +1375,7 @@ hud_parse_env_var(struct hud_context *hud, const char *env) if (strcmp(name, pipeline_statistics_names[i]) == 0) break; if (i < ARRAY_SIZE(pipeline_statistics_names)) { - hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, name, + hud_pipe_query_install(&hud->batch_query, pane, name, PIPE_QUERY_PIPELINE_STATISTICS, i, 0, PIPE_DRIVER_QUERY_TYPE_UINT64, PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, @@ -1218,10 +1386,11 @@ hud_parse_env_var(struct hud_context *hud, const char *env) /* driver queries */ if (!processed) { - if (!hud_driver_query_install(&hud->batch_query, pane, hud->pipe, - name)) { + if (!hud_driver_query_install(&hud->batch_query, pane, + screen, name)) { fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name); fflush(stderr); + added = false; } } } @@ -1264,9 +1433,11 @@ hud_parse_env_var(struct hud_context *hud, const char *env) env += num; strip_hyphens(s); - if (!LIST_IS_EMPTY(&pane->graph_list)) { - strcpy(LIST_ENTRY(struct hud_graph, - pane->graph_list.prev, head)->name, s); + if (added && !list_is_empty(&pane->graph_list)) { + struct hud_graph *graph; + graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head); + strncpy(graph->name, s, sizeof(graph->name)-1); + graph->name[sizeof(graph->name)-1] = 0; } } @@ -1285,10 +1456,11 @@ hud_parse_env_var(struct hud_context *hud, const char *env) break; y += height + hud->font.glyph_height * (pane->num_graphs + 2); + y_simple += hud->font.glyph_height * (pane->num_graphs + 1); height = 100; if (pane && pane->num_graphs) { - LIST_ADDTAIL(&pane->head, &hud->pane_list); + list_addtail(&pane->head, &hud->pane_list); pane = NULL; } break; @@ -1296,11 +1468,12 @@ hud_parse_env_var(struct hud_context *hud, const char *env) case ';': env++; y = 10; + y_simple = 10; x += column_width + hud->font.glyph_width * 9; height = 100; if (pane && pane->num_graphs) { - LIST_ADDTAIL(&pane->head, &hud->pane_list); + list_addtail(&pane->head, &hud->pane_list); pane = NULL; } @@ -1323,12 +1496,20 @@ hud_parse_env_var(struct hud_context *hud, const char *env) if (pane) { if (pane->num_graphs) { - LIST_ADDTAIL(&pane->head, &hud->pane_list); + list_addtail(&pane->head, &hud->pane_list); } else { FREE(pane); } } + + LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { + struct hud_graph *gr; + + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + hud_graph_set_dump_file(gr); + } + } } static void @@ -1376,10 +1557,15 @@ print_help(struct pipe_screen *screen) puts(" the Y axis does not go above the restriction imposed by 'c' while"); puts(" still adjusting the value of the Y axis down when appropriate."); puts(""); + puts(" You can change behavior of the whole HUD by adding these options at"); + puts(" the beginning of the environment variable:"); + puts(" 'simple,' disables all the fancy stuff and only draws text."); + puts(""); puts(" Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\""); puts(""); puts(" Available names:"); puts(" fps"); + puts(" frametime"); puts(" cpu"); for (i = 0; i < num_cpus; i++) @@ -1404,12 +1590,12 @@ print_help(struct pipe_screen *screen) puts(" cs-invocations"); } -#if HAVE_GALLIUM_EXTRA_HUD +#ifdef HAVE_GALLIUM_EXTRA_HUD hud_get_num_disks(1); hud_get_num_nics(1); hud_get_num_cpufreq(1); #endif -#if HAVE_LIBSENSORS +#ifdef HAVE_LIBSENSORS hud_get_num_sensors(1); #endif @@ -1435,61 +1621,49 @@ print_help(struct pipe_screen *screen) fflush(stdout); } -struct hud_context * -hud_create(struct pipe_context *pipe, struct cso_context *cso) +static void +hud_unset_draw_context(struct hud_context *hud) { - struct pipe_screen *screen = pipe->screen; - struct hud_context *hud; - struct pipe_sampler_view view_templ; - unsigned i; - const char *env = debug_get_option("GALLIUM_HUD", NULL); -#ifdef PIPE_OS_UNIX - unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0); - static boolean sig_handled = FALSE; - struct sigaction action = {}; -#endif - huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE); + struct pipe_context *pipe = hud->pipe; - if (!env || !*env) - return NULL; + if (!pipe) + return; - if (strcmp(env, "help") == 0) { - print_help(pipe->screen); - return NULL; + pipe_sampler_view_reference(&hud->font_sampler_view, NULL); + + if (hud->fs_color) { + pipe->delete_fs_state(pipe, hud->fs_color); + hud->fs_color = NULL; + } + if (hud->fs_text) { + pipe->delete_fs_state(pipe, hud->fs_text); + hud->fs_text = NULL; + } + if (hud->vs) { + pipe->delete_vs_state(pipe, hud->vs); + hud->vs = NULL; } - hud = CALLOC_STRUCT(hud_context); - if (!hud) - return NULL; + hud->cso = NULL; + hud->pipe = NULL; +} +static bool +hud_set_draw_context(struct hud_context *hud, struct cso_context *cso) +{ + struct pipe_context *pipe = cso_get_pipe_context(cso); + + assert(!hud->pipe); hud->pipe = pipe; hud->cso = cso; - hud->uploader = u_upload_create(pipe, 256 * 1024, - PIPE_BIND_VERTEX_BUFFER, PIPE_USAGE_STREAM); - - /* font */ - if (!util_font_create(pipe, UTIL_FONT_FIXED_8X13, &hud->font)) { - u_upload_destroy(hud->uploader); - FREE(hud); - return NULL; - } - hud->has_srgb = screen->is_format_supported(screen, - PIPE_FORMAT_B8G8R8A8_SRGB, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_RENDER_TARGET) != 0; - - /* blend state */ - hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA; - - hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA; - hud->alpha_blend.rt[0].blend_enable = 1; - hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD; - hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; - hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; - hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD; - hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; - hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + struct pipe_sampler_view view_templ; + u_sampler_view_default_template( + &view_templ, hud->font.texture, hud->font.texture->format); + hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture, + &view_templ); + if (!hud->font_sampler_view) + goto fail; /* fragment shader */ hud->fs_color = @@ -1518,25 +1692,12 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) if (!tgsi_text_translate(fragment_shader_text, tokens, ARRAY_SIZE(tokens))) { assert(0); - pipe_resource_reference(&hud->font.texture, NULL); - u_upload_destroy(hud->uploader); - FREE(hud); - return NULL; + goto fail; } pipe_shader_state_from_tgsi(&state, tokens); hud->fs_text = pipe->create_fs_state(pipe, &state); } - /* rasterizer */ - hud->rasterizer.half_pixel_center = 1; - hud->rasterizer.bottom_edge_rule = 1; - hud->rasterizer.depth_clip = 1; - hud->rasterizer.line_width = 1; - hud->rasterizer.line_last_pixel = 1; - - hud->rasterizer_aa_lines = hud->rasterizer; - hud->rasterizer_aa_lines.line_smooth = 1; - /* vertex shader */ { static const char *vertex_shader_text = { @@ -1548,17 +1709,17 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) /* [0] = color, * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset) * [2] = (xscale, yscale, 0, 0) */ - "DCL CONST[0..2]\n" + "DCL CONST[0][0..2]\n" "DCL TEMP[0]\n" "IMM[0] FLT32 { -1, 0, 0, 1 }\n" /* v = in * (xscale, yscale) + (xoffset, yoffset) */ - "MAD TEMP[0].xy, IN[0], CONST[2].xyyy, CONST[1].zwww\n" + "MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n" /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */ - "MAD OUT[0].xy, TEMP[0], CONST[1].xyyy, IMM[0].xxxx\n" + "MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n" "MOV OUT[0].zw, IMM[0]\n" - "MOV OUT[1], CONST[0]\n" + "MOV OUT[1], CONST[0][0]\n" "MOV OUT[2], IN[1]\n" "END\n" }; @@ -1567,28 +1728,159 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) struct pipe_shader_state state; if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) { assert(0); - pipe_resource_reference(&hud->font.texture, NULL); - u_upload_destroy(hud->uploader); - FREE(hud); - return NULL; + goto fail; } pipe_shader_state_from_tgsi(&state, tokens); hud->vs = pipe->create_vs_state(pipe, &state); } + return true; + +fail: + hud_unset_draw_context(hud); + fprintf(stderr, "hud: failed to set a draw context"); + return false; +} + +static void +hud_unset_record_context(struct hud_context *hud) +{ + struct pipe_context *pipe = hud->record_pipe; + struct hud_pane *pane, *pane_tmp; + struct hud_graph *graph, *graph_tmp; + + if (!pipe) + return; + + LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) { + LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) { + list_del(&graph->head); + hud_graph_destroy(graph, pipe); + } + list_del(&pane->head); + FREE(pane); + } + + hud_batch_query_cleanup(&hud->batch_query, pipe); + hud->record_pipe = NULL; +} + +static void +hud_set_record_context(struct hud_context *hud, struct pipe_context *pipe) +{ + hud->record_pipe = pipe; +} + +/** + * Create the HUD. + * + * If "share" is non-NULL and GALLIUM_HUD_SHARE=x,y is set, increment the + * reference counter of "share", set "cso" as the recording or drawing context + * according to the environment variable, and return "share". + * This allows sharing the HUD instance within a multi-context share group, + * record queries in one context and draw them in another. + */ +struct hud_context * +hud_create(struct cso_context *cso, struct hud_context *share) +{ + const char *share_env = debug_get_option("GALLIUM_HUD_SHARE", NULL); + unsigned record_ctx = 0, draw_ctx = 0; + + if (share_env && sscanf(share_env, "%u,%u", &record_ctx, &draw_ctx) != 2) + share_env = NULL; + + if (share && share_env) { + /* All contexts in a share group share the HUD instance. + * Only one context can record queries and only one context + * can draw the HUD. + * + * GALLIUM_HUD_SHARE=x,y determines the context indices. + */ + int context_id = p_atomic_inc_return(&share->refcount) - 1; + + if (context_id == record_ctx) { + assert(!share->record_pipe); + hud_set_record_context(share, cso_get_pipe_context(cso)); + } + + if (context_id == draw_ctx) { + assert(!share->pipe); + hud_set_draw_context(share, cso); + } + + return share; + } + + struct pipe_screen *screen = cso_get_pipe_context(cso)->screen; + struct hud_context *hud; + unsigned i; + const char *env = debug_get_option("GALLIUM_HUD", NULL); +#ifdef PIPE_OS_UNIX + unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0); + static boolean sig_handled = FALSE; + struct sigaction action; + + memset(&action, 0, sizeof(action)); +#endif + huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE); + hud_scale = debug_get_num_option("GALLIUM_HUD_SCALE", 1); + + if (!env || !*env) + return NULL; + + if (strcmp(env, "help") == 0) { + print_help(screen); + return NULL; + } + + hud = CALLOC_STRUCT(hud_context); + if (!hud) + return NULL; + + /* font (the context is only used for the texture upload) */ + if (!util_font_create(cso_get_pipe_context(cso), + UTIL_FONT_FIXED_8X13, &hud->font)) { + FREE(hud); + return NULL; + } + + hud->refcount = 1; + hud->has_srgb = screen->is_format_supported(screen, + PIPE_FORMAT_B8G8R8A8_SRGB, + PIPE_TEXTURE_2D, 0, 0, + PIPE_BIND_RENDER_TARGET) != 0; + + /* blend state */ + hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA; + + hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA; + hud->alpha_blend.rt[0].blend_enable = 1; + hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD; + hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD; + hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; + hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + + /* rasterizer */ + hud->rasterizer.half_pixel_center = 1; + hud->rasterizer.bottom_edge_rule = 1; + hud->rasterizer.depth_clip_near = 1; + hud->rasterizer.depth_clip_far = 1; + hud->rasterizer.line_width = 1; + hud->rasterizer.line_last_pixel = 1; + + hud->rasterizer_aa_lines = hud->rasterizer; + hud->rasterizer_aa_lines.line_smooth = 1; + /* vertex elements */ + hud->velems.count = 2; for (i = 0; i < 2; i++) { - hud->velems[i].src_offset = i * 2 * sizeof(float); - hud->velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT; - hud->velems[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso); + hud->velems.velems[i].src_offset = i * 2 * sizeof(float); + hud->velems.velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT; + hud->velems.velems[i].vertex_buffer_index = 0; } - /* sampler view */ - u_sampler_view_default_template( - &view_templ, hud->font.texture, hud->font.texture->format); - hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture, - &view_templ); - /* sampler state (for font drawing) */ hud->font_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; @@ -1599,7 +1891,7 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) hud->constbuf.buffer_size = sizeof(hud->constants); hud->constbuf.user_buffer = &hud->constants; - LIST_INITHEAD(&hud->pane_list); + list_inithead(&hud->pane_list); /* setup sig handler once for all hud contexts */ #ifdef PIPE_OS_UNIX @@ -1617,32 +1909,38 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) } #endif - hud_parse_env_var(hud, env); + if (record_ctx == 0) + hud_set_record_context(hud, cso_get_pipe_context(cso)); + if (draw_ctx == 0) + hud_set_draw_context(hud, cso); + + hud_parse_env_var(hud, screen, env); return hud; } +/** + * Destroy a HUD. If the HUD has several users, decrease the reference counter + * and detach the context from the HUD. + */ void -hud_destroy(struct hud_context *hud) +hud_destroy(struct hud_context *hud, struct cso_context *cso) { - struct pipe_context *pipe = hud->pipe; - struct hud_pane *pane, *pane_tmp; - struct hud_graph *graph, *graph_tmp; + if (!cso || hud->record_pipe == cso_get_pipe_context(cso)) + hud_unset_record_context(hud); - LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) { - LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) { - LIST_DEL(&graph->head); - hud_graph_destroy(graph); - } - LIST_DEL(&pane->head); - FREE(pane); + if (!cso || hud->cso == cso) + hud_unset_draw_context(hud); + + if (p_atomic_dec_zero(&hud->refcount)) { + pipe_resource_reference(&hud->font.texture, NULL); + FREE(hud); } +} - 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); - pipe_sampler_view_reference(&hud->font_sampler_view, NULL); - pipe_resource_reference(&hud->font.texture, NULL); - u_upload_destroy(hud->uploader); - FREE(hud); +void +hud_add_queue_for_monitoring(struct hud_context *hud, + struct util_queue_monitoring *queue_info) +{ + assert(!hud->monitored_queue); + hud->monitored_queue = queue_info; }