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;
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;
};
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;
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
}
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;
}
/**
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;
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, 4 * 1024, 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,
+ (void**)&hud->bg.vertices);
+ pipe_resource_reference(&hud->whitelines.vbuf.buffer, hud->bg.vbuf.buffer);
+ pipe_resource_reference(&hud->text.vbuf.buffer, hud->bg.vbuf.buffer);
+ pipe_resource_reference(&hud->color_prims.vbuf.buffer, hud->bg.vbuf.buffer);
+
+ 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);
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_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
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
* 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);
}
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);
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.
{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 < ARRAY_SIZE(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
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;
+}
+
+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(gr->name));
+ dump_file = malloc(strlen(hud_dump_dir) + sizeof("/") + sizeof(gr->name));
if (dump_file) {
strcpy(dump_file, hud_dump_dir);
- strcat(dump_file, gr->name);
+ strcat(dump_file, "/");
+ strcat_without_spaces(dump_file, gr->name);
gr->fd = fopen(dump_file, "w+");
free(dump_file);
}
}
+#endif
}
/**
{
int i;
- for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';';
+ for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '=';
s++, out++, i++)
*out = *s;
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;
*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);
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;
/*
/* 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
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];
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 {
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;
+ }
+ }
+
if (*env == 0)
break;
width = 251;
ceiling = UINT64_MAX;
dyn_ceiling = false;
+ sort_items = false;
}
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
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("");
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");
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;
}
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;
}
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->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);
}