X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fhud%2Fhud_context.c;h=9dd2fbf17e547ac9d0e8fc3077f25dc7c9c4a564;hb=51f9851753f7605eaa52a7a6982581455e1863ab;hp=6a124f7d716a026cb175dba00c29e9040a05c274;hpb=a62edcce4eb4c800d972817a20ee874bf2a2c3ef;p=mesa.git diff --git a/src/gallium/auxiliary/hud/hud_context.c b/src/gallium/auxiliary/hud/hud_context.c index 6a124f7d716..9dd2fbf17e5 100644 --- a/src/gallium/auxiliary/hud/hud_context.c +++ b/src/gallium/auxiliary/hud/hud_context.c @@ -33,6 +33,8 @@ * Set GALLIUM_HUD=help for more info. */ +#include +#include #include #include "hud/hud_context.h" @@ -41,6 +43,7 @@ #include "cso_cache/cso_context.h" #include "util/u_draw_quad.h" +#include "util/u_format.h" #include "util/u_inlines.h" #include "util/u_memory.h" #include "util/u_math.h" @@ -51,19 +54,21 @@ #include "tgsi/tgsi_text.h" #include "tgsi/tgsi_dump.h" +/* Control the visibility of all HUD contexts */ +static boolean huds_visible = TRUE; 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 alpha_blend; + 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; + struct pipe_rasterizer_state rasterizer, rasterizer_aa_lines; void *vs; struct pipe_vertex_element velems[2]; @@ -92,9 +97,19 @@ struct hud_context { struct pipe_vertex_buffer vbuf; unsigned max_num_vertices; unsigned num_vertices; - } text, bg, whitelines; + unsigned buffer_size; + } text, bg, whitelines, color_prims; + + bool has_srgb; }; +#ifdef PIPE_OS_UNIX +static void +signal_visible_handler(int sig, siginfo_t *siginfo, void *context) +{ + huds_visible = !huds_visible; +} +#endif static void hud_draw_colored_prims(struct hud_context *hud, unsigned prim, @@ -103,7 +118,10 @@ 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; + + assert(size <= hud->color_prims.buffer_size); + memcpy(hud->color_prims.vertices, buffer, size); hud->constants.color[0] = r; hud->constants.color[1] = g; @@ -115,13 +133,14 @@ hud_draw_colored_prims(struct hud_context *hud, unsigned prim, hud->constants.scale[1] = yscale; 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); + 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 @@ -231,28 +250,90 @@ hud_draw_string(struct hud_context *hud, unsigned x, unsigned y, } static void -number_to_human_readable(uint64_t num, boolean is_in_bytes, char *out) +number_to_human_readable(uint64_t num, enum pipe_driver_query_type type, + char *out) { static const char *byte_units[] = - {"", " KB", " MB", " GB", " TB", " PB", " EB"}; + {" B", " KB", " MB", " GB", " TB", " PB", " EB"}; static const char *metric_units[] = {"", " k", " M", " G", " T", " P", " E"}; - const char **units = is_in_bytes ? byte_units : metric_units; - double divisor = is_in_bytes ? 1024 : 1000; - int unit = 0; + static const char *time_units[] = + {" us", " ms", " s"}; /* based on microseconds */ + static const char *hz_units[] = + {" Hz", " KHz", " MHz", " GHz"}; + static const char *percent_units[] = {"%"}; + static const char *dbm_units[] = {" (-dBm)"}; + static const char *temperature_units[] = {" C"}; + static const char *volt_units[] = {" mV", " V"}; + static const char *amp_units[] = {" mA", " A"}; + static const char *watt_units[] = {" mW", " W"}; + + const char **units; + unsigned max_unit; + double divisor = (type == PIPE_DRIVER_QUERY_TYPE_BYTES) ? 1024 : 1000; + unsigned unit = 0; double d = num; - while (d > divisor) { + switch (type) { + case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS: + max_unit = ARRAY_SIZE(time_units)-1; + units = time_units; + break; + case PIPE_DRIVER_QUERY_TYPE_VOLTS: + max_unit = ARRAY_SIZE(volt_units)-1; + units = volt_units; + break; + case PIPE_DRIVER_QUERY_TYPE_AMPS: + max_unit = ARRAY_SIZE(amp_units)-1; + units = amp_units; + break; + case PIPE_DRIVER_QUERY_TYPE_DBM: + max_unit = ARRAY_SIZE(dbm_units)-1; + units = dbm_units; + break; + case PIPE_DRIVER_QUERY_TYPE_TEMPERATURE: + max_unit = ARRAY_SIZE(temperature_units)-1; + units = temperature_units; + break; + case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE: + max_unit = ARRAY_SIZE(percent_units)-1; + units = percent_units; + break; + case PIPE_DRIVER_QUERY_TYPE_BYTES: + max_unit = ARRAY_SIZE(byte_units)-1; + units = byte_units; + break; + case PIPE_DRIVER_QUERY_TYPE_HZ: + max_unit = ARRAY_SIZE(hz_units)-1; + units = hz_units; + break; + case PIPE_DRIVER_QUERY_TYPE_WATTS: + max_unit = ARRAY_SIZE(watt_units)-1; + units = watt_units; + break; + default: + max_unit = ARRAY_SIZE(metric_units)-1; + units = metric_units; + } + + while (d > divisor && unit < max_unit) { d /= divisor; unit++; } - if (d >= 100 || d == (int)d) + /* Round to 3 decimal places so as not to print trailing zeros. */ + if (d*1000 != (int)(d*1000)) + d = round(d * 1000) / 1000; + + /* Show at least 4 digits with at most 3 decimal places, but not zeros. */ + if (d >= 1000 || d == (int)d) sprintf(out, "%.0f%s", d, units[unit]); - else if (d >= 10 || d*10 == (int)(d*10)) + else if (d >= 100 || d*10 == (int)(d*10)) sprintf(out, "%.1f%s", d, units[unit]); - else + else if (d >= 10 || d*100 == (int)(d*100)) sprintf(out, "%.2f%s", d, units[unit]); + else + sprintf(out, "%.3f%s", d, units[unit]); } static void @@ -288,6 +369,7 @@ hud_pane_accumulate_vertices(struct hud_context *hud, float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2; unsigned i, num = 0; char str[32]; + const unsigned last_line = pane->last_line; /* draw background */ hud_draw_background_quad(hud, @@ -295,14 +377,15 @@ hud_pane_accumulate_vertices(struct hud_context *hud, pane->x2, pane->y2); /* draw numbers on the right-hand side */ - for (i = 0; i < 6; i++) { + for (i = 0; i <= last_line; i++) { unsigned x = pane->x2 + 2; - unsigned y = pane->inner_y1 + pane->inner_height * (5 - i) / 5 - + unsigned y = pane->inner_y1 + + pane->inner_height * (last_line - i) / last_line - hud->font.glyph_height / 2; - number_to_human_readable(pane->max_value * i / 5, - pane->uses_byte_units, str); - hud_draw_string(hud, x, y, str); + number_to_human_readable(pane->max_value * i / last_line, + pane->type, str); + hud_draw_string(hud, x, y, "%s", str); } /* draw info below the pane */ @@ -311,8 +394,7 @@ hud_pane_accumulate_vertices(struct hud_context *hud, unsigned x = pane->x1 + 2; unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; - number_to_human_readable(gr->current_value, - pane->uses_byte_units, str); + number_to_human_readable(gr->current_value, pane->type, str); hud_draw_string(hud, x, y, " %s: %s", gr->name, str); i++; } @@ -340,8 +422,9 @@ hud_pane_accumulate_vertices(struct hud_context *hud, line_verts[num++] = (float) pane->y2; /* draw horizontal lines inside the graph */ - for (i = 0; i <= 5; i++) { - float y = round((pane->max_value * i / 5.0) * pane->yscale + pane->inner_y2); + for (i = 0; i <= last_line; i++) { + float y = round((pane->max_value * i / (double)last_line) * + pane->yscale + pane->inner_y2); assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices); line_verts[num++] = pane->x1; @@ -378,15 +461,13 @@ 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, - &v->vbuf.buffer_offset, &v->vbuf.buffer, - (void**)&v->vertices); + v->buffer_size = stride * num_vertices; } /** @@ -404,36 +485,52 @@ 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; + struct hud_graph *gr, *next; + + if (!huds_visible) + return; hud->fb_width = tex->width0; hud->fb_height = tex->height0; hud->constants.two_div_fb_width = 2.0f / hud->fb_width; hud->constants.two_div_fb_height = 2.0f / hud->fb_height; - cso_save_framebuffer(cso); - cso_save_sample_mask(cso); - cso_save_min_samples(cso); - cso_save_blend(cso); - cso_save_depth_stencil_alpha(cso); - cso_save_fragment_shader(cso); - cso_save_sampler_views(cso, PIPE_SHADER_FRAGMENT); - cso_save_samplers(cso, PIPE_SHADER_FRAGMENT); - cso_save_rasterizer(cso); - cso_save_viewport(cso); - cso_save_stream_outputs(cso); - cso_save_geometry_shader(cso); - cso_save_tessctrl_shader(cso); - cso_save_tesseval_shader(cso); - cso_save_vertex_shader(cso); - cso_save_vertex_elements(cso); - cso_save_aux_vertex_buffer_slot(cso); + cso_save_state(cso, (CSO_BIT_FRAMEBUFFER | + CSO_BIT_SAMPLE_MASK | + CSO_BIT_MIN_SAMPLES | + CSO_BIT_BLEND | + CSO_BIT_DEPTH_STENCIL_ALPHA | + CSO_BIT_FRAGMENT_SHADER | + CSO_BIT_FRAGMENT_SAMPLER_VIEWS | + CSO_BIT_FRAGMENT_SAMPLERS | + CSO_BIT_RASTERIZER | + CSO_BIT_VIEWPORT | + CSO_BIT_STREAM_OUTPUTS | + CSO_BIT_GEOMETRY_SHADER | + CSO_BIT_TESSCTRL_SHADER | + CSO_BIT_TESSEVAL_SHADER | + CSO_BIT_VERTEX_SHADER | + CSO_BIT_VERTEX_ELEMENTS | + CSO_BIT_AUX_VERTEX_BUFFER_SLOT | + CSO_BIT_PAUSE_QUERIES | + CSO_BIT_RENDER_CONDITION)); cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); - cso_save_render_condition(cso); /* set states */ memset(&surf_templ, 0, sizeof(surf_templ)); surf_templ.format = tex->format; + + /* Without this, AA lines look thinner if they are between 2 pixels + * because the alpha is 0.5 on both pixels. (it's ugly) + * + * sRGB makes the width of all AA lines look the same. + */ + if (hud->has_srgb) { + enum pipe_format srgb_format = util_format_srgb(tex->format); + + if (srgb_format != PIPE_FORMAT_NONE) + surf_templ.format = srgb_format; + } surf = pipe->create_surface(pipe, tex, &surf_templ); memset(&fb, 0, sizeof(fb)); @@ -453,7 +550,6 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) cso_set_framebuffer(cso, &fb); cso_set_sample_mask(cso, ~0); cso_set_min_samples(cso, 1); - cso_set_blend(cso, &hud->alpha_blend); cso_set_depth_stencil_alpha(cso, &hud->dsa); cso_set_rasterizer(cso, &hud->rasterizer); cso_set_viewport(cso, &viewport); @@ -470,23 +566,77 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); /* prepare vertex buffers */ - hud_alloc_vertices(hud, &hud->bg, 4 * 128, 2 * sizeof(float)); - hud_alloc_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float)); - hud_alloc_vertices(hud, &hud->text, 4 * 512, 4 * sizeof(float)); + 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(hud->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) { + goto out; + } + + 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); + 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); + u_upload_unmap(pipe->stream_uploader); /* draw accumulated vertices for background quads */ + cso_set_blend(cso, &hud->alpha_blend); cso_set_fragment_shader_handle(hud->cso, hud->fs_color); if (hud->bg.num_vertices) { @@ -504,9 +654,11 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) &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 white lines */ + cso_set_blend(cso, &hud->no_blend); + hud->constants.color[0] = 1; hud->constants.color[1] = 1; hud->constants.color[2] = 1; @@ -523,45 +675,47 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) 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); + pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, 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->text.vbuf.buffer.resource, NULL); /* draw the rest */ + cso_set_rasterizer(cso, &hud->rasterizer_aa_lines); LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { if (pane) hud_pane_draw_colored_objects(hud, pane); } - /* restore states */ - cso_restore_framebuffer(cso); - cso_restore_sample_mask(cso); - cso_restore_min_samples(cso); - cso_restore_blend(cso); - cso_restore_depth_stencil_alpha(cso); - cso_restore_fragment_shader(cso); - cso_restore_sampler_views(cso, PIPE_SHADER_FRAGMENT); - cso_restore_samplers(cso, PIPE_SHADER_FRAGMENT); - cso_restore_rasterizer(cso); - cso_restore_viewport(cso); - cso_restore_stream_outputs(cso); - cso_restore_tessctrl_shader(cso); - cso_restore_tesseval_shader(cso); - cso_restore_geometry_shader(cso); - cso_restore_vertex_shader(cso); - cso_restore_vertex_elements(cso); - cso_restore_aux_vertex_buffer_slot(cso); +out: + cso_restore_state(cso); cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); - cso_restore_render_condition(cso); pipe_surface_reference(&surf, NULL); + + /* Start queries. */ + hud_batch_query_begin(hud->batch_query); + + 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); + } + } +} + +static void +fixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10) +{ + if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0) + *exp10 = (*exp10 / 1000) * 1024; } /** @@ -571,7 +725,75 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex) void hud_pane_set_max_value(struct hud_pane *pane, uint64_t value) { - pane->max_value = value; + double leftmost_digit; + uint64_t exp10; + int i; + + /* The following code determines the max_value in the graph as well as + * how many describing lines are drawn. The max_value is rounded up, + * so that all drawn numbers are rounded for readability. + * We want to print multiples of a simple number instead of multiples of + * hard-to-read numbers like 1.753. + */ + + /* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't + * overflow. (11 is safe) */ + exp10 = 1; + for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) { + exp10 *= 10; + fixup_bytes(pane->type, i + 1, &exp10); + } + + leftmost_digit = DIV_ROUND_UP(value, exp10); + + /* Round 9 to 10. */ + if (leftmost_digit == 9) { + leftmost_digit = 1; + exp10 *= 10; + fixup_bytes(pane->type, i + 1, &exp10); + } + + switch ((unsigned)leftmost_digit) { + case 1: + pane->last_line = 5; /* lines in +1/5 increments */ + break; + case 2: + pane->last_line = 8; /* lines in +1/4 increments. */ + break; + case 3: + case 4: + pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments */ + break; + case 5: + case 6: + case 7: + case 8: + pane->last_line = leftmost_digit; /* lines in +1 increments */ + break; + default: + assert(0); + } + + /* Truncate {3,4} to {2.5, 3.5} if possible. */ + for (i = 3; i <= 4; i++) { + if (leftmost_digit == i && value <= (i - 0.5) * exp10) { + leftmost_digit = i - 0.5; + pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments. */ + } + } + + /* Truncate 2 to a multiple of 0.2 in (1, 1.6] if possible. */ + if (leftmost_digit == 2) { + for (i = 1; i <= 3; i++) { + if (value <= (1 + i*0.2) * exp10) { + leftmost_digit = 1 + i*0.2; + pane->last_line = 5 + i; /* lines in +1/5 increments. */ + break; + } + } + } + + pane->max_value = leftmost_digit * exp10; pane->yscale = -(int)pane->inner_height / (float)pane->max_value; } @@ -604,7 +826,7 @@ 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, unsigned period, uint64_t max_value, uint64_t ceiling, - boolean dyn_ceiling) + boolean dyn_ceiling, boolean sort_items) { struct hud_pane *pane = CALLOC_STRUCT(hud_pane); @@ -626,12 +848,24 @@ hud_pane_create(unsigned x1, unsigned y1, unsigned x2, unsigned y2, pane->ceiling = ceiling; pane->dyn_ceiling = dyn_ceiling; pane->dyn_ceil_last_ran = 0; + pane->sort_items = sort_items; pane->initial_max_value = max_value; hud_pane_set_max_value(pane, max_value); LIST_INITHEAD(&pane->graph_list); return pane; } +/* replace '-' with a space */ +static void +strip_hyphens(char *s) +{ + while (*s) { + if (*s == '-') + *s = ' '; + s++; + } +} + /** * Add a graph to an existing pane. * One pane can contain multiple graphs over each other. @@ -645,26 +879,29 @@ hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr) {0, 1, 1}, {1, 0, 1}, {1, 1, 0}, - {0.5, 0.5, 1}, - {0.5, 0.5, 0.5}, + {0.5, 1, 0.5}, + {1, 0.5, 0.5}, + {0.5, 1, 1}, + {1, 0.5, 1}, + {1, 1, 0.5}, + {0, 0.5, 0}, + {0.5, 0, 0}, + {0, 0.5, 0.5}, + {0.5, 0, 0.5}, + {0.5, 0.5, 0}, }; - char *name = gr->name; + unsigned color = pane->next_color % ARRAY_SIZE(colors); - /* replace '-' with a space */ - while (*name) { - if (*name == '-') - *name = ' '; - name++; - } + strip_hyphens(gr->name); - assert(pane->num_graphs < Elements(colors)); gr->vertices = MALLOC(pane->max_num_vertices * sizeof(float) * 2); - gr->color[0] = colors[pane->num_graphs][0]; - gr->color[1] = colors[pane->num_graphs][1]; - gr->color[2] = colors[pane->num_graphs][2]; + gr->color[0] = colors[color][0]; + gr->color[1] = colors[color][1]; + gr->color[2] = colors[color][2]; gr->pane = pane; LIST_ADDTAIL(&gr->head, &pane->graph_list); pane->num_graphs++; + pane->next_color++; } void @@ -673,6 +910,9 @@ hud_graph_add_value(struct hud_graph *gr, uint64_t 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->index == gr->pane->max_num_vertices) { gr->vertices[0] = 0; gr->vertices[1] = gr->vertices[(gr->index-1)*2+1]; @@ -700,9 +940,46 @@ hud_graph_destroy(struct hud_graph *graph) FREE(graph->vertices); if (graph->free_query_data) graph->free_query_data(graph->query_data); + if (graph->fd) + fclose(graph->fd); FREE(graph); } +static void strcat_without_spaces(char *dst, const char *src) +{ + dst += strlen(dst); + while (*src) { + if (*src == ' ') + *dst++ = '_'; + else + *dst++ = *src; + src++; + } + *dst = 0; +} + +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)); + if (dump_file) { + strcpy(dump_file, hud_dump_dir); + strcat(dump_file, "/"); + strcat_without_spaces(dump_file, gr->name); + gr->fd = fopen(dump_file, "w+"); + if (gr->fd) + setvbuf(gr->fd, NULL, _IOLBF, 0); + free(dump_file); + } + } +#endif +} + /** * Read a string from the environment variable. * The separators "+", ",", ":", and ";" terminate the string. @@ -713,22 +990,26 @@ parse_string(const char *s, char *out) { int i; - for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';'; + for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '='; s++, out++, i++) *out = *s; *out = 0; - if (*s && !i) + if (*s && !i) { fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while " "parsing a string\n", *s, *s); + fflush(stderr); + } + return i; } static char * read_pane_settings(char *str, unsigned * const x, unsigned * const y, unsigned * const width, unsigned * const height, - uint64_t * const ceiling, boolean * const dyn_ceiling) + uint64_t * const ceiling, boolean * const dyn_ceiling, + boolean *reset_colors, boolean *sort_items) { char *ret = str; unsigned tmp; @@ -779,8 +1060,21 @@ read_pane_settings(char *str, unsigned * const x, unsigned * const y, *dyn_ceiling = true; break; + case 'r': + ++str; + ret = str; + *reset_colors = true; + break; + + case 's': + ++str; + ret = str; + *sort_items = true; + break; + default: fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *str); + fflush(stderr); } } @@ -819,6 +1113,8 @@ hud_parse_env_var(struct hud_context *hud, const char *env) uint64_t ceiling = UINT64_MAX; unsigned column_width = 251; boolean dyn_ceiling = false; + boolean reset_colors = false; + boolean sort_items = false; const char *period_env; /* @@ -839,7 +1135,7 @@ hud_parse_env_var(struct hud_context *hud, const char *env) /* check for explicit location, size and etc. settings */ name = read_pane_settings(name_a, &x, &y, &width, &height, &ceiling, - &dyn_ceiling); + &dyn_ceiling, &reset_colors, &sort_items); /* * Keep track of overall column width to avoid pane overlapping in case @@ -850,12 +1146,20 @@ hud_parse_env_var(struct hud_context *hud, const char *env) if (!pane) { pane = hud_pane_create(x, y, x + width, y + height, period, 10, - ceiling, dyn_ceiling); + ceiling, dyn_ceiling, sort_items); if (!pane) return; } + if (reset_colors) { + pane->next_color = 0; + reset_colors = false; + } + /* Add a graph. */ +#if HAVE_GALLIUM_EXTRA_HUD || HAVE_LIBSENSORS + char arg_name[64]; +#endif /* IF YOU CHANGE THIS, UPDATE print_help! */ if (strcmp(name, "fps") == 0) { hud_fps_graph_install(pane); @@ -866,15 +1170,85 @@ hud_parse_env_var(struct hud_context *hud, const char *env) else if (sscanf(name, "cpu%u%s", &i, s) == 1) { hud_cpu_graph_install(pane, i); } + else if (strcmp(name, "API-thread-busy") == 0) { + hud_api_thread_busy_install(pane); + } +#if HAVE_GALLIUM_EXTRA_HUD + else if (sscanf(name, "nic-rx-%s", arg_name) == 1) { + hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX); + } + else if (sscanf(name, "nic-tx-%s", arg_name) == 1) { + hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_TX); + } + else if (sscanf(name, "nic-rssi-%s", arg_name) == 1) { + hud_nic_graph_install(pane, arg_name, NIC_RSSI_DBM); + pane->type = PIPE_DRIVER_QUERY_TYPE_DBM; + } + else if (sscanf(name, "diskstat-rd-%s", arg_name) == 1) { + hud_diskstat_graph_install(pane, arg_name, DISKSTAT_RD); + pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES; + } + else if (sscanf(name, "diskstat-wr-%s", arg_name) == 1) { + hud_diskstat_graph_install(pane, arg_name, DISKSTAT_WR); + pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES; + } + else if (sscanf(name, "cpufreq-min-cpu%u", &i) == 1) { + hud_cpufreq_graph_install(pane, i, CPUFREQ_MINIMUM); + pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; + } + else if (sscanf(name, "cpufreq-cur-cpu%u", &i) == 1) { + hud_cpufreq_graph_install(pane, i, CPUFREQ_CURRENT); + pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; + } + else if (sscanf(name, "cpufreq-max-cpu%u", &i) == 1) { + hud_cpufreq_graph_install(pane, i, CPUFREQ_MAXIMUM); + pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; + } +#endif +#if HAVE_LIBSENSORS + else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) { + hud_sensors_temp_graph_install(pane, arg_name, + SENSORS_TEMP_CURRENT); + pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE; + } + else if (sscanf(name, "sensors_temp_cr-%s", arg_name) == 1) { + hud_sensors_temp_graph_install(pane, arg_name, + SENSORS_TEMP_CRITICAL); + pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE; + } + else if (sscanf(name, "sensors_volt_cu-%s", arg_name) == 1) { + hud_sensors_temp_graph_install(pane, arg_name, + SENSORS_VOLTAGE_CURRENT); + pane->type = PIPE_DRIVER_QUERY_TYPE_VOLTS; + } + else if (sscanf(name, "sensors_curr_cu-%s", arg_name) == 1) { + hud_sensors_temp_graph_install(pane, arg_name, + SENSORS_CURRENT_CURRENT); + pane->type = PIPE_DRIVER_QUERY_TYPE_AMPS; + } + else if (sscanf(name, "sensors_pow_cu-%s", arg_name) == 1) { + hud_sensors_temp_graph_install(pane, arg_name, + SENSORS_POWER_CURRENT); + pane->type = PIPE_DRIVER_QUERY_TYPE_WATTS; + } +#endif else if (strcmp(name, "samples-passed") == 0 && has_occlusion_query(hud->pipe->screen)) { - hud_pipe_query_install(pane, hud->pipe, "samples-passed", - PIPE_QUERY_OCCLUSION_COUNTER, 0, 0, FALSE); + 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, + 0); } else if (strcmp(name, "primitives-generated") == 0 && has_streamout(hud->pipe->screen)) { - hud_pipe_query_install(pane, hud->pipe, "primitives-generated", - PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0, FALSE); + 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, + 0); } else { boolean processed = FALSE; @@ -895,21 +1269,25 @@ hud_parse_env_var(struct hud_context *hud, const char *env) "ds-invocations", "cs-invocations" }; - for (i = 0; i < Elements(pipeline_statistics_names); ++i) + for (i = 0; i < ARRAY_SIZE(pipeline_statistics_names); ++i) if (strcmp(name, pipeline_statistics_names[i]) == 0) break; - if (i < Elements(pipeline_statistics_names)) { - hud_pipe_query_install(pane, hud->pipe, name, + if (i < ARRAY_SIZE(pipeline_statistics_names)) { + hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, name, PIPE_QUERY_PIPELINE_STATISTICS, i, - 0, FALSE); + 0, PIPE_DRIVER_QUERY_TYPE_UINT64, + 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); + fflush(stderr); } } } @@ -920,6 +1298,7 @@ hud_parse_env_var(struct hud_context *hud, const char *env) if (!pane) { fprintf(stderr, "gallium_hud: syntax error: unexpected ':', " "expected a name\n"); + fflush(stderr); break; } @@ -932,7 +1311,30 @@ hud_parse_env_var(struct hud_context *hud, const char *env) } else { fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) " - "after ':'\n", *env, *env); + "after ':'\n", *env, *env); + fflush(stderr); + } + } + + if (*env == '=') { + env++; + + if (!pane) { + fprintf(stderr, "gallium_hud: syntax error: unexpected '=', " + "expected a name\n"); + fflush(stderr); + break; + } + + num = parse_string(env, s); + env += num; + + strip_hyphens(s); + if (!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; } } @@ -947,6 +1349,9 @@ hud_parse_env_var(struct hud_context *hud, const char *env) case ',': env++; + if (!pane) + break; + y += height + hud->font.glyph_height * (pane->num_graphs + 2); height = 100; @@ -959,7 +1364,7 @@ hud_parse_env_var(struct hud_context *hud, const char *env) case ';': env++; y = 10; - x += column_width + hud->font.glyph_width * 7; + x += column_width + hud->font.glyph_width * 9; height = 100; if (pane && pane->num_graphs) { @@ -973,12 +1378,14 @@ hud_parse_env_var(struct hud_context *hud, const char *env) default: fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env); + fflush(stderr); } /* Reset to defaults for the next pane in case these were modified. */ width = 251; ceiling = UINT64_MAX; dyn_ceiling = false; + sort_items = false; } @@ -990,6 +1397,14 @@ hud_parse_env_var(struct hud_context *hud, const char *env) 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 @@ -1008,6 +1423,8 @@ print_help(struct pipe_screen *screen) puts(" for the given pane."); puts(" ',' creates a new pane below the last one."); puts(" ';' creates a new pane at the top of the next column."); + puts(" '=' followed by a string, changes the name of the last data source"); + puts(" to that string"); puts(""); puts(" Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\""); puts(""); @@ -1028,6 +1445,8 @@ print_help(struct pipe_screen *screen) puts(" the ceiling allows, the value is clamped."); puts(" 'd' activates dynamic Y axis readjustment to set the value of"); puts(" the Y axis to match the highest value still visible in the graph."); + puts(" 'r' resets the color counter (the next color will be green)"); + puts(" 's' sort items below graphs in descending order"); puts(""); puts(" If 'c' and 'd' modifiers are used simultaneously, both are in effect:"); puts(" the Y axis does not go above the restriction imposed by 'c' while"); @@ -1061,13 +1480,30 @@ print_help(struct pipe_screen *screen) puts(" cs-invocations"); } +#if HAVE_GALLIUM_EXTRA_HUD + hud_get_num_disks(1); + hud_get_num_nics(1); + hud_get_num_cpufreq(1); +#endif +#if HAVE_LIBSENSORS + hud_get_num_sensors(1); +#endif + if (screen->get_driver_query_info){ + boolean skipping = false; struct pipe_driver_query_info info; num_queries = screen->get_driver_query_info(screen, 0, NULL); for (i = 0; i < num_queries; i++){ screen->get_driver_query_info(screen, i, &info); - printf(" %s\n", info.name); + if (info.flags & PIPE_DRIVER_QUERY_FLAG_DONT_LIST) { + if (!skipping) + puts(" ..."); + skipping = true; + } else { + printf(" %s\n", info.name); + skipping = false; + } } } @@ -1078,10 +1514,17 @@ print_help(struct pipe_screen *screen) struct hud_context * hud_create(struct pipe_context *pipe, struct cso_context *cso) { + 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); if (!env || !*env) return NULL; @@ -1097,17 +1540,21 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) hud->pipe = pipe; hud->cso = cso; - hud->uploader = u_upload_create(pipe, 256 * 1024, 16, - PIPE_BIND_VERTEX_BUFFER); /* 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; @@ -1130,6 +1577,7 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) "FRAG\n" "DCL IN[0], GENERIC[0], LINEAR\n" "DCL SAMP[0]\n" + "DCL SVIEW[0], RECT, FLOAT\n" "DCL OUT[0], COLOR[0]\n" "DCL TEMP[0]\n" @@ -1139,16 +1587,15 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) }; struct tgsi_token tokens[1000]; - struct pipe_shader_state state = {tokens}; + struct pipe_shader_state state; - if (!tgsi_text_translate(fragment_shader_text, tokens, Elements(tokens))) { + 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; } - + pipe_shader_state_from_tgsi(&state, tokens); hud->fs_text = pipe->create_fs_state(pipe, &state); } @@ -1159,6 +1606,9 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) 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 = { @@ -1186,16 +1636,14 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) }; struct tgsi_token tokens[1000]; - struct pipe_shader_state state = {tokens}; - - if (!tgsi_text_translate(vertex_shader_text, tokens, Elements(tokens))) { + 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; } - + pipe_shader_state_from_tgsi(&state, tokens); hud->vs = pipe->create_vs_state(pipe, &state); } @@ -1224,6 +1672,22 @@ hud_create(struct pipe_context *pipe, struct cso_context *cso) LIST_INITHEAD(&hud->pane_list); + /* setup sig handler once for all hud contexts */ +#ifdef PIPE_OS_UNIX + if (!sig_handled && signo != 0) { + action.sa_sigaction = &signal_visible_handler; + action.sa_flags = SA_SIGINFO; + + if (signo >= NSIG) + fprintf(stderr, "gallium_hud: invalid signal %u\n", signo); + else if (sigaction(signo, &action, NULL) < 0) + fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo); + fflush(stderr); + + sig_handled = TRUE; + } +#endif + hud_parse_env_var(hud, env); return hud; } @@ -1244,11 +1708,11 @@ 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); pipe_sampler_view_reference(&hud->font_sampler_view, NULL); pipe_resource_reference(&hud->font.texture, NULL); - u_upload_destroy(hud->uploader); FREE(hud); }