1 /**************************************************************************
3 * Copyright 2013 Marek Olšák <maraeo@gmail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 /* This head-up display module can draw transparent graphs on top of what
29 * the app is rendering, visualizing various data like framerate, cpu load,
30 * performance counters, etc. It can be hook up into any state tracker.
32 * The HUD is controlled with the GALLIUM_HUD environment variable.
33 * Set GALLIUM_HUD=help for more info.
40 #include "hud/hud_context.h"
41 #include "hud/hud_private.h"
44 #include "cso_cache/cso_context.h"
45 #include "util/u_draw_quad.h"
46 #include "util/u_format.h"
47 #include "util/u_inlines.h"
48 #include "util/u_memory.h"
49 #include "util/u_math.h"
50 #include "util/u_sampler.h"
51 #include "util/u_simple_shaders.h"
52 #include "util/u_string.h"
53 #include "util/u_upload_mgr.h"
54 #include "tgsi/tgsi_text.h"
55 #include "tgsi/tgsi_dump.h"
57 /* Control the visibility of all HUD contexts */
58 static boolean huds_visible = TRUE;
61 struct pipe_context *pipe;
62 struct cso_context *cso;
64 struct hud_batch_query_context *batch_query;
65 struct list_head pane_list;
68 struct pipe_blend_state no_blend, alpha_blend;
69 struct pipe_depth_stencil_alpha_state dsa;
70 void *fs_color, *fs_text;
71 struct pipe_rasterizer_state rasterizer, rasterizer_aa_lines;
73 struct pipe_vertex_element velems[2];
76 struct util_font font;
77 struct pipe_sampler_view *font_sampler_view;
78 struct pipe_sampler_state font_sampler_state;
80 /* VS constant buffer */
83 float two_div_fb_width;
84 float two_div_fb_height;
89 struct pipe_constant_buffer constbuf;
91 unsigned fb_width, fb_height;
93 /* vertices for text and background drawing are accumulated here and then
94 * drawn all at once */
97 struct pipe_vertex_buffer vbuf;
98 unsigned max_num_vertices;
99 unsigned num_vertices;
100 unsigned buffer_size;
101 } text, bg, whitelines, color_prims;
108 signal_visible_handler(int sig, siginfo_t *siginfo, void *context)
110 huds_visible = !huds_visible;
115 hud_draw_colored_prims(struct hud_context *hud, unsigned prim,
116 float *buffer, unsigned num_vertices,
117 float r, float g, float b, float a,
118 int xoffset, int yoffset, float yscale)
120 struct cso_context *cso = hud->cso;
121 unsigned size = num_vertices * hud->color_prims.vbuf.stride;
123 assert(size <= hud->color_prims.buffer_size);
124 memcpy(hud->color_prims.vertices, buffer, size);
126 hud->constants.color[0] = r;
127 hud->constants.color[1] = g;
128 hud->constants.color[2] = b;
129 hud->constants.color[3] = a;
130 hud->constants.translate[0] = (float) xoffset;
131 hud->constants.translate[1] = (float) yoffset;
132 hud->constants.scale[0] = 1;
133 hud->constants.scale[1] = yscale;
134 cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
136 cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso),
137 1, &hud->color_prims.vbuf);
138 cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
139 cso_draw_arrays(cso, prim, 0, num_vertices);
141 hud->color_prims.vertices += size / sizeof(float);
142 hud->color_prims.vbuf.buffer_offset += size;
143 hud->color_prims.buffer_size -= size;
147 hud_draw_colored_quad(struct hud_context *hud, unsigned prim,
148 unsigned x1, unsigned y1, unsigned x2, unsigned y2,
149 float r, float g, float b, float a)
152 (float) x1, (float) y1,
153 (float) x1, (float) y2,
154 (float) x2, (float) y2,
155 (float) x2, (float) y1,
158 hud_draw_colored_prims(hud, prim, buffer, 4, r, g, b, a, 0, 0, 1);
162 hud_draw_background_quad(struct hud_context *hud,
163 unsigned x1, unsigned y1, unsigned x2, unsigned y2)
165 float *vertices = hud->bg.vertices + hud->bg.num_vertices*2;
168 assert(hud->bg.num_vertices + 4 <= hud->bg.max_num_vertices);
170 vertices[num++] = (float) x1;
171 vertices[num++] = (float) y1;
173 vertices[num++] = (float) x1;
174 vertices[num++] = (float) y2;
176 vertices[num++] = (float) x2;
177 vertices[num++] = (float) y2;
179 vertices[num++] = (float) x2;
180 vertices[num++] = (float) y1;
182 hud->bg.num_vertices += num/2;
186 hud_draw_string(struct hud_context *hud, unsigned x, unsigned y,
187 const char *str, ...)
191 float *vertices = hud->text.vertices + hud->text.num_vertices*4;
196 util_vsnprintf(buf, sizeof(buf), str, ap);
202 hud_draw_background_quad(hud,
204 x + strlen(buf)*hud->font.glyph_width,
205 y + hud->font.glyph_height);
210 unsigned x2 = x + hud->font.glyph_width;
211 unsigned y2 = y + hud->font.glyph_height;
212 unsigned tx1 = (*s % 16) * hud->font.glyph_width;
213 unsigned ty1 = (*s / 16) * hud->font.glyph_height;
214 unsigned tx2 = tx1 + hud->font.glyph_width;
215 unsigned ty2 = ty1 + hud->font.glyph_height;
218 x += hud->font.glyph_width;
223 assert(hud->text.num_vertices + num/4 + 4 <= hud->text.max_num_vertices);
225 vertices[num++] = (float) x1;
226 vertices[num++] = (float) y1;
227 vertices[num++] = (float) tx1;
228 vertices[num++] = (float) ty1;
230 vertices[num++] = (float) x1;
231 vertices[num++] = (float) y2;
232 vertices[num++] = (float) tx1;
233 vertices[num++] = (float) ty2;
235 vertices[num++] = (float) x2;
236 vertices[num++] = (float) y2;
237 vertices[num++] = (float) tx2;
238 vertices[num++] = (float) ty2;
240 vertices[num++] = (float) x2;
241 vertices[num++] = (float) y1;
242 vertices[num++] = (float) tx2;
243 vertices[num++] = (float) ty1;
245 x += hud->font.glyph_width;
249 hud->text.num_vertices += num/4;
253 number_to_human_readable(uint64_t num, enum pipe_driver_query_type type,
256 static const char *byte_units[] =
257 {" B", " KB", " MB", " GB", " TB", " PB", " EB"};
258 static const char *metric_units[] =
259 {"", " k", " M", " G", " T", " P", " E"};
260 static const char *time_units[] =
261 {" us", " ms", " s"}; /* based on microseconds */
262 static const char *hz_units[] =
263 {" Hz", " KHz", " MHz", " GHz"};
264 static const char *percent_units[] = {"%"};
265 static const char *dbm_units[] = {" (-dBm)"};
266 static const char *temperature_units[] = {" C"};
267 static const char *volt_units[] = {" mV", " V"};
268 static const char *amp_units[] = {" mA", " A"};
269 static const char *watt_units[] = {" mW", " W"};
273 double divisor = (type == PIPE_DRIVER_QUERY_TYPE_BYTES) ? 1024 : 1000;
278 case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS:
279 max_unit = ARRAY_SIZE(time_units)-1;
282 case PIPE_DRIVER_QUERY_TYPE_VOLTS:
283 max_unit = ARRAY_SIZE(volt_units)-1;
286 case PIPE_DRIVER_QUERY_TYPE_AMPS:
287 max_unit = ARRAY_SIZE(amp_units)-1;
290 case PIPE_DRIVER_QUERY_TYPE_DBM:
291 max_unit = ARRAY_SIZE(dbm_units)-1;
294 case PIPE_DRIVER_QUERY_TYPE_TEMPERATURE:
295 max_unit = ARRAY_SIZE(temperature_units)-1;
296 units = temperature_units;
298 case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE:
299 max_unit = ARRAY_SIZE(percent_units)-1;
300 units = percent_units;
302 case PIPE_DRIVER_QUERY_TYPE_BYTES:
303 max_unit = ARRAY_SIZE(byte_units)-1;
306 case PIPE_DRIVER_QUERY_TYPE_HZ:
307 max_unit = ARRAY_SIZE(hz_units)-1;
310 case PIPE_DRIVER_QUERY_TYPE_WATTS:
311 max_unit = ARRAY_SIZE(watt_units)-1;
315 max_unit = ARRAY_SIZE(metric_units)-1;
316 units = metric_units;
319 while (d > divisor && unit < max_unit) {
324 /* Round to 3 decimal places so as not to print trailing zeros. */
325 if (d*1000 != (int)(d*1000))
326 d = round(d * 1000) / 1000;
328 /* Show at least 4 digits with at most 3 decimal places, but not zeros. */
329 if (d >= 1000 || d == (int)d)
330 sprintf(out, "%.0f%s", d, units[unit]);
331 else if (d >= 100 || d*10 == (int)(d*10))
332 sprintf(out, "%.1f%s", d, units[unit]);
333 else if (d >= 10 || d*100 == (int)(d*100))
334 sprintf(out, "%.2f%s", d, units[unit]);
336 sprintf(out, "%.3f%s", d, units[unit]);
340 hud_draw_graph_line_strip(struct hud_context *hud, const struct hud_graph *gr,
341 unsigned xoffset, unsigned yoffset, float yscale)
343 if (gr->num_vertices <= 1)
346 assert(gr->index <= gr->num_vertices);
348 hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP,
349 gr->vertices, gr->index,
350 gr->color[0], gr->color[1], gr->color[2], 1,
351 xoffset + (gr->pane->max_num_vertices - gr->index - 1) * 2 - 1,
354 if (gr->num_vertices <= gr->index)
357 hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP,
358 gr->vertices + gr->index*2,
359 gr->num_vertices - gr->index,
360 gr->color[0], gr->color[1], gr->color[2], 1,
361 xoffset - gr->index*2 - 1, yoffset, yscale);
365 hud_pane_accumulate_vertices(struct hud_context *hud,
366 const struct hud_pane *pane)
368 struct hud_graph *gr;
369 float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2;
372 const unsigned last_line = pane->last_line;
374 /* draw background */
375 hud_draw_background_quad(hud,
379 /* draw numbers on the right-hand side */
380 for (i = 0; i <= last_line; i++) {
381 unsigned x = pane->x2 + 2;
382 unsigned y = pane->inner_y1 +
383 pane->inner_height * (last_line - i) / last_line -
384 hud->font.glyph_height / 2;
386 number_to_human_readable(pane->max_value * i / last_line,
388 hud_draw_string(hud, x, y, "%s", str);
391 /* draw info below the pane */
393 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
394 unsigned x = pane->x1 + 2;
395 unsigned y = pane->y2 + 2 + i*hud->font.glyph_height;
397 number_to_human_readable(gr->current_value, pane->type, str);
398 hud_draw_string(hud, x, y, " %s: %s", gr->name, str);
403 assert(hud->whitelines.num_vertices + num/2 + 8 <= hud->whitelines.max_num_vertices);
404 line_verts[num++] = (float) pane->x1;
405 line_verts[num++] = (float) pane->y1;
406 line_verts[num++] = (float) pane->x2;
407 line_verts[num++] = (float) pane->y1;
409 line_verts[num++] = (float) pane->x2;
410 line_verts[num++] = (float) pane->y1;
411 line_verts[num++] = (float) pane->x2;
412 line_verts[num++] = (float) pane->y2;
414 line_verts[num++] = (float) pane->x1;
415 line_verts[num++] = (float) pane->y2;
416 line_verts[num++] = (float) pane->x2;
417 line_verts[num++] = (float) pane->y2;
419 line_verts[num++] = (float) pane->x1;
420 line_verts[num++] = (float) pane->y1;
421 line_verts[num++] = (float) pane->x1;
422 line_verts[num++] = (float) pane->y2;
424 /* draw horizontal lines inside the graph */
425 for (i = 0; i <= last_line; i++) {
426 float y = round((pane->max_value * i / (double)last_line) *
427 pane->yscale + pane->inner_y2);
429 assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices);
430 line_verts[num++] = pane->x1;
431 line_verts[num++] = y;
432 line_verts[num++] = pane->x2;
433 line_verts[num++] = y;
436 hud->whitelines.num_vertices += num/2;
440 hud_pane_draw_colored_objects(struct hud_context *hud,
441 const struct hud_pane *pane)
443 struct hud_graph *gr;
446 /* draw colored quads below the pane */
448 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
449 unsigned x = pane->x1 + 2;
450 unsigned y = pane->y2 + 2 + i*hud->font.glyph_height;
452 hud_draw_colored_quad(hud, PIPE_PRIM_QUADS, x + 1, y + 1, x + 12, y + 13,
453 gr->color[0], gr->color[1], gr->color[2], 1);
457 /* draw the line strips */
458 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
459 hud_draw_graph_line_strip(hud, gr, pane->inner_x1, pane->inner_y2, pane->yscale);
464 hud_prepare_vertices(struct hud_context *hud, struct vertex_queue *v,
465 unsigned num_vertices, unsigned stride)
468 v->max_num_vertices = num_vertices;
469 v->vbuf.stride = stride;
470 v->buffer_size = stride * num_vertices;
474 * Draw the HUD to the texture \p tex.
475 * The texture is usually the back buffer being displayed.
478 hud_draw(struct hud_context *hud, struct pipe_resource *tex)
480 struct cso_context *cso = hud->cso;
481 struct pipe_context *pipe = hud->pipe;
482 struct pipe_framebuffer_state fb;
483 struct pipe_surface surf_templ, *surf;
484 struct pipe_viewport_state viewport;
485 const struct pipe_sampler_state *sampler_states[] =
486 { &hud->font_sampler_state };
487 struct hud_pane *pane;
488 struct hud_graph *gr, *next;
493 hud->fb_width = tex->width0;
494 hud->fb_height = tex->height0;
495 hud->constants.two_div_fb_width = 2.0f / hud->fb_width;
496 hud->constants.two_div_fb_height = 2.0f / hud->fb_height;
498 cso_save_state(cso, (CSO_BIT_FRAMEBUFFER |
499 CSO_BIT_SAMPLE_MASK |
500 CSO_BIT_MIN_SAMPLES |
502 CSO_BIT_DEPTH_STENCIL_ALPHA |
503 CSO_BIT_FRAGMENT_SHADER |
504 CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
505 CSO_BIT_FRAGMENT_SAMPLERS |
508 CSO_BIT_STREAM_OUTPUTS |
509 CSO_BIT_GEOMETRY_SHADER |
510 CSO_BIT_TESSCTRL_SHADER |
511 CSO_BIT_TESSEVAL_SHADER |
512 CSO_BIT_VERTEX_SHADER |
513 CSO_BIT_VERTEX_ELEMENTS |
514 CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
515 CSO_BIT_PAUSE_QUERIES |
516 CSO_BIT_RENDER_CONDITION));
517 cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
520 memset(&surf_templ, 0, sizeof(surf_templ));
521 surf_templ.format = tex->format;
523 /* Without this, AA lines look thinner if they are between 2 pixels
524 * because the alpha is 0.5 on both pixels. (it's ugly)
526 * sRGB makes the width of all AA lines look the same.
529 enum pipe_format srgb_format = util_format_srgb(tex->format);
531 if (srgb_format != PIPE_FORMAT_NONE)
532 surf_templ.format = srgb_format;
534 surf = pipe->create_surface(pipe, tex, &surf_templ);
536 memset(&fb, 0, sizeof(fb));
540 fb.width = hud->fb_width;
541 fb.height = hud->fb_height;
543 viewport.scale[0] = 0.5f * hud->fb_width;
544 viewport.scale[1] = 0.5f * hud->fb_height;
545 viewport.scale[2] = 1.0f;
546 viewport.translate[0] = 0.5f * hud->fb_width;
547 viewport.translate[1] = 0.5f * hud->fb_height;
548 viewport.translate[2] = 0.0f;
550 cso_set_framebuffer(cso, &fb);
551 cso_set_sample_mask(cso, ~0);
552 cso_set_min_samples(cso, 1);
553 cso_set_depth_stencil_alpha(cso, &hud->dsa);
554 cso_set_rasterizer(cso, &hud->rasterizer);
555 cso_set_viewport(cso, &viewport);
556 cso_set_stream_outputs(cso, 0, NULL, NULL);
557 cso_set_tessctrl_shader_handle(cso, NULL);
558 cso_set_tesseval_shader_handle(cso, NULL);
559 cso_set_geometry_shader_handle(cso, NULL);
560 cso_set_vertex_shader_handle(cso, hud->vs);
561 cso_set_vertex_elements(cso, 2, hud->velems);
562 cso_set_render_condition(cso, NULL, FALSE, 0);
563 cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1,
564 &hud->font_sampler_view);
565 cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states);
566 cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
568 /* prepare vertex buffers */
569 hud_prepare_vertices(hud, &hud->bg, 16 * 256, 2 * sizeof(float));
570 hud_prepare_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float));
571 hud_prepare_vertices(hud, &hud->text, 16 * 1024, 4 * sizeof(float));
572 hud_prepare_vertices(hud, &hud->color_prims, 32 * 1024, 2 * sizeof(float));
574 /* Allocate everything once and divide the storage into 3 portions
575 * manually, because u_upload_alloc can unmap memory from previous calls.
577 u_upload_alloc(hud->pipe->stream_uploader, 0,
578 hud->bg.buffer_size +
579 hud->whitelines.buffer_size +
580 hud->text.buffer_size +
581 hud->color_prims.buffer_size,
582 16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource,
583 (void**)&hud->bg.vertices);
584 if (!hud->bg.vertices) {
588 pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
589 pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
590 pipe_resource_reference(&hud->color_prims.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
592 hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset +
594 hud->whitelines.vertices = hud->bg.vertices +
595 hud->bg.buffer_size / sizeof(float);
597 hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset +
598 hud->whitelines.buffer_size;
599 hud->text.vertices = hud->whitelines.vertices +
600 hud->whitelines.buffer_size / sizeof(float);
602 hud->color_prims.vbuf.buffer_offset = hud->text.vbuf.buffer_offset +
603 hud->text.buffer_size;
604 hud->color_prims.vertices = hud->text.vertices +
605 hud->text.buffer_size / sizeof(float);
607 /* prepare all graphs */
608 hud_batch_query_update(hud->batch_query);
610 LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
611 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
612 gr->query_new_value(gr);
615 if (pane->sort_items) {
616 LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) {
617 /* ignore the last one */
618 if (&gr->head == pane->graph_list.prev)
621 /* This is an incremental bubble sort, because we only do one pass
622 * per frame. It will eventually reach an equilibrium.
624 if (gr->current_value <
625 LIST_ENTRY(struct hud_graph, next, head)->current_value) {
627 LIST_ADD(&gr->head, &next->head);
632 hud_pane_accumulate_vertices(hud, pane);
635 /* unmap the uploader's vertex buffer before drawing */
636 u_upload_unmap(pipe->stream_uploader);
638 /* draw accumulated vertices for background quads */
639 cso_set_blend(cso, &hud->alpha_blend);
640 cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
642 if (hud->bg.num_vertices) {
643 hud->constants.color[0] = 0;
644 hud->constants.color[1] = 0;
645 hud->constants.color[2] = 0;
646 hud->constants.color[3] = 0.666f;
647 hud->constants.translate[0] = 0;
648 hud->constants.translate[1] = 0;
649 hud->constants.scale[0] = 1;
650 hud->constants.scale[1] = 1;
652 cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
653 cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
655 cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices);
657 pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL);
659 /* draw accumulated vertices for white lines */
660 cso_set_blend(cso, &hud->no_blend);
662 hud->constants.color[0] = 1;
663 hud->constants.color[1] = 1;
664 hud->constants.color[2] = 1;
665 hud->constants.color[3] = 1;
666 hud->constants.translate[0] = 0;
667 hud->constants.translate[1] = 0;
668 hud->constants.scale[0] = 1;
669 hud->constants.scale[1] = 1;
670 cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
672 if (hud->whitelines.num_vertices) {
673 cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
674 &hud->whitelines.vbuf);
675 cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
676 cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices);
678 pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL);
680 /* draw accumulated vertices for text */
681 cso_set_blend(cso, &hud->alpha_blend);
682 if (hud->text.num_vertices) {
683 cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
685 cso_set_fragment_shader_handle(hud->cso, hud->fs_text);
686 cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices);
688 pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL);
691 cso_set_rasterizer(cso, &hud->rasterizer_aa_lines);
692 LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
694 hud_pane_draw_colored_objects(hud, pane);
698 cso_restore_state(cso);
699 cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
701 pipe_surface_reference(&surf, NULL);
704 hud_batch_query_begin(hud->batch_query);
706 LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
707 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
715 fixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10)
717 if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0)
718 *exp10 = (*exp10 / 1000) * 1024;
722 * Set the maximum value for the Y axis of the graph.
723 * This scales the graph accordingly.
726 hud_pane_set_max_value(struct hud_pane *pane, uint64_t value)
728 double leftmost_digit;
732 /* The following code determines the max_value in the graph as well as
733 * how many describing lines are drawn. The max_value is rounded up,
734 * so that all drawn numbers are rounded for readability.
735 * We want to print multiples of a simple number instead of multiples of
736 * hard-to-read numbers like 1.753.
739 /* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't
740 * overflow. (11 is safe) */
742 for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) {
744 fixup_bytes(pane->type, i + 1, &exp10);
747 leftmost_digit = DIV_ROUND_UP(value, exp10);
750 if (leftmost_digit == 9) {
753 fixup_bytes(pane->type, i + 1, &exp10);
756 switch ((unsigned)leftmost_digit) {
758 pane->last_line = 5; /* lines in +1/5 increments */
761 pane->last_line = 8; /* lines in +1/4 increments. */
765 pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments */
771 pane->last_line = leftmost_digit; /* lines in +1 increments */
777 /* Truncate {3,4} to {2.5, 3.5} if possible. */
778 for (i = 3; i <= 4; i++) {
779 if (leftmost_digit == i && value <= (i - 0.5) * exp10) {
780 leftmost_digit = i - 0.5;
781 pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments. */
785 /* Truncate 2 to a multiple of 0.2 in (1, 1.6] if possible. */
786 if (leftmost_digit == 2) {
787 for (i = 1; i <= 3; i++) {
788 if (value <= (1 + i*0.2) * exp10) {
789 leftmost_digit = 1 + i*0.2;
790 pane->last_line = 5 + i; /* lines in +1/5 increments. */
796 pane->max_value = leftmost_digit * exp10;
797 pane->yscale = -(int)pane->inner_height / (float)pane->max_value;
801 hud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane)
806 if (pane->dyn_ceil_last_ran != gr->index) {
807 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
808 for (i = 0; i < gr->num_vertices; ++i) {
809 tmp = gr->vertices[i * 2 + 1] > tmp ?
810 gr->vertices[i * 2 + 1] : tmp;
814 /* Avoid setting it lower than the initial starting height. */
815 tmp = tmp > pane->initial_max_value ? tmp : pane->initial_max_value;
816 hud_pane_set_max_value(pane, tmp);
820 * Mark this adjustment run so we could avoid repeating a full update
821 * again needlessly in case the pane has more than one graph.
823 pane->dyn_ceil_last_ran = gr->index;
826 static struct hud_pane *
827 hud_pane_create(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
828 unsigned period, uint64_t max_value, uint64_t ceiling,
829 boolean dyn_ceiling, boolean sort_items)
831 struct hud_pane *pane = CALLOC_STRUCT(hud_pane);
840 pane->inner_x1 = x1 + 1;
841 pane->inner_x2 = x2 - 1;
842 pane->inner_y1 = y1 + 1;
843 pane->inner_y2 = y2 - 1;
844 pane->inner_width = pane->inner_x2 - pane->inner_x1;
845 pane->inner_height = pane->inner_y2 - pane->inner_y1;
846 pane->period = period;
847 pane->max_num_vertices = (x2 - x1 + 2) / 2;
848 pane->ceiling = ceiling;
849 pane->dyn_ceiling = dyn_ceiling;
850 pane->dyn_ceil_last_ran = 0;
851 pane->sort_items = sort_items;
852 pane->initial_max_value = max_value;
853 hud_pane_set_max_value(pane, max_value);
854 LIST_INITHEAD(&pane->graph_list);
858 /* replace '-' with a space */
860 strip_hyphens(char *s)
870 * Add a graph to an existing pane.
871 * One pane can contain multiple graphs over each other.
874 hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr)
876 static const float colors[][3] = {
893 unsigned color = pane->next_color % ARRAY_SIZE(colors);
895 strip_hyphens(gr->name);
897 gr->vertices = MALLOC(pane->max_num_vertices * sizeof(float) * 2);
898 gr->color[0] = colors[color][0];
899 gr->color[1] = colors[color][1];
900 gr->color[2] = colors[color][2];
902 LIST_ADDTAIL(&gr->head, &pane->graph_list);
908 hud_graph_add_value(struct hud_graph *gr, uint64_t value)
910 gr->current_value = value;
911 value = value > gr->pane->ceiling ? gr->pane->ceiling : value;
914 fprintf(gr->fd, "%" PRIu64 "\n", value);
916 if (gr->index == gr->pane->max_num_vertices) {
918 gr->vertices[1] = gr->vertices[(gr->index-1)*2+1];
921 gr->vertices[(gr->index)*2+0] = (float) (gr->index * 2);
922 gr->vertices[(gr->index)*2+1] = (float) value;
925 if (gr->num_vertices < gr->pane->max_num_vertices) {
929 if (gr->pane->dyn_ceiling == true) {
930 hud_pane_update_dyn_ceiling(gr, gr->pane);
932 if (value > gr->pane->max_value) {
933 hud_pane_set_max_value(gr->pane, value);
938 hud_graph_destroy(struct hud_graph *graph)
940 FREE(graph->vertices);
941 if (graph->free_query_data)
942 graph->free_query_data(graph->query_data);
948 static void strcat_without_spaces(char *dst, const char *src)
962 hud_graph_set_dump_file(struct hud_graph *gr)
964 #ifndef PIPE_OS_WINDOWS
965 const char *hud_dump_dir = getenv("GALLIUM_HUD_DUMP_DIR");
968 if (hud_dump_dir && access(hud_dump_dir, W_OK) == 0) {
969 dump_file = malloc(strlen(hud_dump_dir) + sizeof("/") + sizeof(gr->name));
971 strcpy(dump_file, hud_dump_dir);
972 strcat(dump_file, "/");
973 strcat_without_spaces(dump_file, gr->name);
974 gr->fd = fopen(dump_file, "w+");
976 setvbuf(gr->fd, NULL, _IOLBF, 0);
984 * Read a string from the environment variable.
985 * The separators "+", ",", ":", and ";" terminate the string.
986 * Return the number of read characters.
989 parse_string(const char *s, char *out)
993 for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '=';
1000 fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while "
1001 "parsing a string\n", *s, *s);
1009 read_pane_settings(char *str, unsigned * const x, unsigned * const y,
1010 unsigned * const width, unsigned * const height,
1011 uint64_t * const ceiling, boolean * const dyn_ceiling,
1012 boolean *reset_colors, boolean *sort_items)
1017 while (*str == '.') {
1022 *x = strtoul(str, &ret, 10);
1028 *y = strtoul(str, &ret, 10);
1034 tmp = strtoul(str, &ret, 10);
1035 *width = tmp > 80 ? tmp : 80; /* 80 is chosen arbitrarily */
1040 * Prevent setting height to less than 50. If the height is set to less,
1041 * the text of the Y axis labels on the graph will start overlapping.
1045 tmp = strtoul(str, &ret, 10);
1046 *height = tmp > 50 ? tmp : 50;
1052 tmp = strtoul(str, &ret, 10);
1053 *ceiling = tmp > 10 ? tmp : 10;
1060 *dyn_ceiling = true;
1066 *reset_colors = true;
1076 fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *str);
1086 has_occlusion_query(struct pipe_screen *screen)
1088 return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) != 0;
1092 has_streamout(struct pipe_screen *screen)
1094 return screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0;
1098 has_pipeline_stats_query(struct pipe_screen *screen)
1100 return screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS) != 0;
1104 hud_parse_env_var(struct hud_context *hud, const char *env)
1107 char name_a[256], s[256];
1109 struct hud_pane *pane = NULL;
1110 unsigned x = 10, y = 10;
1111 unsigned width = 251, height = 100;
1112 unsigned period = 500 * 1000; /* default period (1/2 second) */
1113 uint64_t ceiling = UINT64_MAX;
1114 unsigned column_width = 251;
1115 boolean dyn_ceiling = false;
1116 boolean reset_colors = false;
1117 boolean sort_items = false;
1118 const char *period_env;
1121 * The GALLIUM_HUD_PERIOD env var sets the graph update rate.
1122 * The env var is in seconds (a float).
1123 * Zero means update after every frame.
1125 period_env = getenv("GALLIUM_HUD_PERIOD");
1127 float p = (float) atof(period_env);
1129 period = (unsigned) (p * 1000 * 1000);
1133 while ((num = parse_string(env, name_a)) != 0) {
1136 /* check for explicit location, size and etc. settings */
1137 name = read_pane_settings(name_a, &x, &y, &width, &height, &ceiling,
1138 &dyn_ceiling, &reset_colors, &sort_items);
1141 * Keep track of overall column width to avoid pane overlapping in case
1142 * later we create a new column while the bottom pane in the current
1143 * column is less wide than the rest of the panes in it.
1145 column_width = width > column_width ? width : column_width;
1148 pane = hud_pane_create(x, y, x + width, y + height, period, 10,
1149 ceiling, dyn_ceiling, sort_items);
1155 pane->next_color = 0;
1156 reset_colors = false;
1160 #if HAVE_GALLIUM_EXTRA_HUD || HAVE_LIBSENSORS
1163 /* IF YOU CHANGE THIS, UPDATE print_help! */
1164 if (strcmp(name, "fps") == 0) {
1165 hud_fps_graph_install(pane);
1167 else if (strcmp(name, "cpu") == 0) {
1168 hud_cpu_graph_install(pane, ALL_CPUS);
1170 else if (sscanf(name, "cpu%u%s", &i, s) == 1) {
1171 hud_cpu_graph_install(pane, i);
1173 else if (strcmp(name, "API-thread-busy") == 0) {
1174 hud_api_thread_busy_install(pane);
1176 #if HAVE_GALLIUM_EXTRA_HUD
1177 else if (sscanf(name, "nic-rx-%s", arg_name) == 1) {
1178 hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX);
1180 else if (sscanf(name, "nic-tx-%s", arg_name) == 1) {
1181 hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_TX);
1183 else if (sscanf(name, "nic-rssi-%s", arg_name) == 1) {
1184 hud_nic_graph_install(pane, arg_name, NIC_RSSI_DBM);
1185 pane->type = PIPE_DRIVER_QUERY_TYPE_DBM;
1187 else if (sscanf(name, "diskstat-rd-%s", arg_name) == 1) {
1188 hud_diskstat_graph_install(pane, arg_name, DISKSTAT_RD);
1189 pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES;
1191 else if (sscanf(name, "diskstat-wr-%s", arg_name) == 1) {
1192 hud_diskstat_graph_install(pane, arg_name, DISKSTAT_WR);
1193 pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES;
1195 else if (sscanf(name, "cpufreq-min-cpu%u", &i) == 1) {
1196 hud_cpufreq_graph_install(pane, i, CPUFREQ_MINIMUM);
1197 pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
1199 else if (sscanf(name, "cpufreq-cur-cpu%u", &i) == 1) {
1200 hud_cpufreq_graph_install(pane, i, CPUFREQ_CURRENT);
1201 pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
1203 else if (sscanf(name, "cpufreq-max-cpu%u", &i) == 1) {
1204 hud_cpufreq_graph_install(pane, i, CPUFREQ_MAXIMUM);
1205 pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
1209 else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) {
1210 hud_sensors_temp_graph_install(pane, arg_name,
1211 SENSORS_TEMP_CURRENT);
1212 pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE;
1214 else if (sscanf(name, "sensors_temp_cr-%s", arg_name) == 1) {
1215 hud_sensors_temp_graph_install(pane, arg_name,
1216 SENSORS_TEMP_CRITICAL);
1217 pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE;
1219 else if (sscanf(name, "sensors_volt_cu-%s", arg_name) == 1) {
1220 hud_sensors_temp_graph_install(pane, arg_name,
1221 SENSORS_VOLTAGE_CURRENT);
1222 pane->type = PIPE_DRIVER_QUERY_TYPE_VOLTS;
1224 else if (sscanf(name, "sensors_curr_cu-%s", arg_name) == 1) {
1225 hud_sensors_temp_graph_install(pane, arg_name,
1226 SENSORS_CURRENT_CURRENT);
1227 pane->type = PIPE_DRIVER_QUERY_TYPE_AMPS;
1229 else if (sscanf(name, "sensors_pow_cu-%s", arg_name) == 1) {
1230 hud_sensors_temp_graph_install(pane, arg_name,
1231 SENSORS_POWER_CURRENT);
1232 pane->type = PIPE_DRIVER_QUERY_TYPE_WATTS;
1235 else if (strcmp(name, "samples-passed") == 0 &&
1236 has_occlusion_query(hud->pipe->screen)) {
1237 hud_pipe_query_install(&hud->batch_query, pane, hud->pipe,
1239 PIPE_QUERY_OCCLUSION_COUNTER, 0, 0,
1240 PIPE_DRIVER_QUERY_TYPE_UINT64,
1241 PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
1244 else if (strcmp(name, "primitives-generated") == 0 &&
1245 has_streamout(hud->pipe->screen)) {
1246 hud_pipe_query_install(&hud->batch_query, pane, hud->pipe,
1247 "primitives-generated",
1248 PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0,
1249 PIPE_DRIVER_QUERY_TYPE_UINT64,
1250 PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
1254 boolean processed = FALSE;
1256 /* pipeline statistics queries */
1257 if (has_pipeline_stats_query(hud->pipe->screen)) {
1258 static const char *pipeline_statistics_names[] =
1265 "clipper-invocations",
1266 "clipper-primitives-generated",
1272 for (i = 0; i < ARRAY_SIZE(pipeline_statistics_names); ++i)
1273 if (strcmp(name, pipeline_statistics_names[i]) == 0)
1275 if (i < ARRAY_SIZE(pipeline_statistics_names)) {
1276 hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, name,
1277 PIPE_QUERY_PIPELINE_STATISTICS, i,
1278 0, PIPE_DRIVER_QUERY_TYPE_UINT64,
1279 PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
1285 /* driver queries */
1287 if (!hud_driver_query_install(&hud->batch_query, pane, hud->pipe,
1289 fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name);
1299 fprintf(stderr, "gallium_hud: syntax error: unexpected ':', "
1300 "expected a name\n");
1305 num = parse_string(env, s);
1308 if (num && sscanf(s, "%u", &i) == 1) {
1309 hud_pane_set_max_value(pane, i);
1310 pane->initial_max_value = i;
1313 fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) "
1314 "after ':'\n", *env, *env);
1323 fprintf(stderr, "gallium_hud: syntax error: unexpected '=', "
1324 "expected a name\n");
1329 num = parse_string(env, s);
1333 if (!LIST_IS_EMPTY(&pane->graph_list)) {
1334 struct hud_graph *graph;
1335 graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head);
1336 strncpy(graph->name, s, sizeof(graph->name)-1);
1337 graph->name[sizeof(graph->name)-1] = 0;
1344 /* parse a separator */
1355 y += height + hud->font.glyph_height * (pane->num_graphs + 2);
1358 if (pane && pane->num_graphs) {
1359 LIST_ADDTAIL(&pane->head, &hud->pane_list);
1367 x += column_width + hud->font.glyph_width * 9;
1370 if (pane && pane->num_graphs) {
1371 LIST_ADDTAIL(&pane->head, &hud->pane_list);
1375 /* Starting a new column; reset column width. */
1380 fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env);
1384 /* Reset to defaults for the next pane in case these were modified. */
1386 ceiling = UINT64_MAX;
1387 dyn_ceiling = false;
1393 if (pane->num_graphs) {
1394 LIST_ADDTAIL(&pane->head, &hud->pane_list);
1401 LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
1402 struct hud_graph *gr;
1404 LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
1405 hud_graph_set_dump_file(gr);
1411 print_help(struct pipe_screen *screen)
1413 int i, num_queries, num_cpus = hud_get_num_cpus();
1415 puts("Syntax: GALLIUM_HUD=name1[+name2][...][:value1][,nameI...][;nameJ...]");
1417 puts(" Names are identifiers of data sources which will be drawn as graphs");
1418 puts(" in panes. Multiple graphs can be drawn in the same pane.");
1419 puts(" There can be multiple panes placed in rows and columns.");
1421 puts(" '+' separates names which will share a pane.");
1422 puts(" ':[value]' specifies the initial maximum value of the Y axis");
1423 puts(" for the given pane.");
1424 puts(" ',' creates a new pane below the last one.");
1425 puts(" ';' creates a new pane at the top of the next column.");
1426 puts(" '=' followed by a string, changes the name of the last data source");
1427 puts(" to that string");
1429 puts(" Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\"");
1431 puts(" Additionally, by prepending '.[identifier][value]' modifiers to");
1432 puts(" a name, it is possible to explicitly set the location and size");
1433 puts(" of a pane, along with limiting overall maximum value of the");
1434 puts(" Y axis and activating dynamic readjustment of the Y axis.");
1435 puts(" Several modifiers may be applied to the same pane simultaneously.");
1437 puts(" 'x[value]' sets the location of the pane on the x axis relative");
1438 puts(" to the upper-left corner of the viewport, in pixels.");
1439 puts(" 'y[value]' sets the location of the pane on the y axis relative");
1440 puts(" to the upper-left corner of the viewport, in pixels.");
1441 puts(" 'w[value]' sets width of the graph pixels.");
1442 puts(" 'h[value]' sets height of the graph in pixels.");
1443 puts(" 'c[value]' sets the ceiling of the value of the Y axis.");
1444 puts(" If the graph needs to draw values higher than");
1445 puts(" the ceiling allows, the value is clamped.");
1446 puts(" 'd' activates dynamic Y axis readjustment to set the value of");
1447 puts(" the Y axis to match the highest value still visible in the graph.");
1448 puts(" 'r' resets the color counter (the next color will be green)");
1449 puts(" 's' sort items below graphs in descending order");
1451 puts(" If 'c' and 'd' modifiers are used simultaneously, both are in effect:");
1452 puts(" the Y axis does not go above the restriction imposed by 'c' while");
1453 puts(" still adjusting the value of the Y axis down when appropriate.");
1455 puts(" Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\"");
1457 puts(" Available names:");
1461 for (i = 0; i < num_cpus; i++)
1462 printf(" cpu%i\n", i);
1464 if (has_occlusion_query(screen))
1465 puts(" samples-passed");
1466 if (has_streamout(screen))
1467 puts(" primitives-generated");
1469 if (has_pipeline_stats_query(screen)) {
1470 puts(" ia-vertices");
1471 puts(" ia-primitives");
1472 puts(" vs-invocations");
1473 puts(" gs-invocations");
1474 puts(" gs-primitives");
1475 puts(" clipper-invocations");
1476 puts(" clipper-primitives-generated");
1477 puts(" ps-invocations");
1478 puts(" hs-invocations");
1479 puts(" ds-invocations");
1480 puts(" cs-invocations");
1483 #if HAVE_GALLIUM_EXTRA_HUD
1484 hud_get_num_disks(1);
1485 hud_get_num_nics(1);
1486 hud_get_num_cpufreq(1);
1489 hud_get_num_sensors(1);
1492 if (screen->get_driver_query_info){
1493 boolean skipping = false;
1494 struct pipe_driver_query_info info;
1495 num_queries = screen->get_driver_query_info(screen, 0, NULL);
1497 for (i = 0; i < num_queries; i++){
1498 screen->get_driver_query_info(screen, i, &info);
1499 if (info.flags & PIPE_DRIVER_QUERY_FLAG_DONT_LIST) {
1504 printf(" %s\n", info.name);
1514 struct hud_context *
1515 hud_create(struct pipe_context *pipe, struct cso_context *cso)
1517 struct pipe_screen *screen = pipe->screen;
1518 struct hud_context *hud;
1519 struct pipe_sampler_view view_templ;
1521 const char *env = debug_get_option("GALLIUM_HUD", NULL);
1523 unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0);
1524 static boolean sig_handled = FALSE;
1525 struct sigaction action = {};
1527 huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE);
1532 if (strcmp(env, "help") == 0) {
1533 print_help(pipe->screen);
1537 hud = CALLOC_STRUCT(hud_context);
1545 if (!util_font_create(pipe, UTIL_FONT_FIXED_8X13, &hud->font)) {
1550 hud->has_srgb = screen->is_format_supported(screen,
1551 PIPE_FORMAT_B8G8R8A8_SRGB,
1553 PIPE_BIND_RENDER_TARGET) != 0;
1556 hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA;
1558 hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA;
1559 hud->alpha_blend.rt[0].blend_enable = 1;
1560 hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD;
1561 hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
1562 hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
1563 hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD;
1564 hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
1565 hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
1567 /* fragment shader */
1569 util_make_fragment_passthrough_shader(pipe,
1570 TGSI_SEMANTIC_COLOR,
1571 TGSI_INTERPOLATE_CONSTANT,
1575 /* Read a texture and do .xxxx swizzling. */
1576 static const char *fragment_shader_text = {
1578 "DCL IN[0], GENERIC[0], LINEAR\n"
1580 "DCL SVIEW[0], RECT, FLOAT\n"
1581 "DCL OUT[0], COLOR[0]\n"
1584 "TEX TEMP[0], IN[0], SAMP[0], RECT\n"
1585 "MOV OUT[0], TEMP[0].xxxx\n"
1589 struct tgsi_token tokens[1000];
1590 struct pipe_shader_state state;
1592 if (!tgsi_text_translate(fragment_shader_text, tokens, ARRAY_SIZE(tokens))) {
1594 pipe_resource_reference(&hud->font.texture, NULL);
1598 pipe_shader_state_from_tgsi(&state, tokens);
1599 hud->fs_text = pipe->create_fs_state(pipe, &state);
1603 hud->rasterizer.half_pixel_center = 1;
1604 hud->rasterizer.bottom_edge_rule = 1;
1605 hud->rasterizer.depth_clip = 1;
1606 hud->rasterizer.line_width = 1;
1607 hud->rasterizer.line_last_pixel = 1;
1609 hud->rasterizer_aa_lines = hud->rasterizer;
1610 hud->rasterizer_aa_lines.line_smooth = 1;
1614 static const char *vertex_shader_text = {
1617 "DCL OUT[0], POSITION\n"
1618 "DCL OUT[1], COLOR[0]\n" /* color */
1619 "DCL OUT[2], GENERIC[0]\n" /* texcoord */
1621 * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset)
1622 * [2] = (xscale, yscale, 0, 0) */
1625 "IMM[0] FLT32 { -1, 0, 0, 1 }\n"
1627 /* v = in * (xscale, yscale) + (xoffset, yoffset) */
1628 "MAD TEMP[0].xy, IN[0], CONST[2].xyyy, CONST[1].zwww\n"
1629 /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */
1630 "MAD OUT[0].xy, TEMP[0], CONST[1].xyyy, IMM[0].xxxx\n"
1631 "MOV OUT[0].zw, IMM[0]\n"
1633 "MOV OUT[1], CONST[0]\n"
1634 "MOV OUT[2], IN[1]\n"
1638 struct tgsi_token tokens[1000];
1639 struct pipe_shader_state state;
1640 if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) {
1642 pipe_resource_reference(&hud->font.texture, NULL);
1646 pipe_shader_state_from_tgsi(&state, tokens);
1647 hud->vs = pipe->create_vs_state(pipe, &state);
1650 /* vertex elements */
1651 for (i = 0; i < 2; i++) {
1652 hud->velems[i].src_offset = i * 2 * sizeof(float);
1653 hud->velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT;
1654 hud->velems[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
1658 u_sampler_view_default_template(
1659 &view_templ, hud->font.texture, hud->font.texture->format);
1660 hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture,
1663 /* sampler state (for font drawing) */
1664 hud->font_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1665 hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1666 hud->font_sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1667 hud->font_sampler_state.normalized_coords = 0;
1670 hud->constbuf.buffer_size = sizeof(hud->constants);
1671 hud->constbuf.user_buffer = &hud->constants;
1673 LIST_INITHEAD(&hud->pane_list);
1675 /* setup sig handler once for all hud contexts */
1677 if (!sig_handled && signo != 0) {
1678 action.sa_sigaction = &signal_visible_handler;
1679 action.sa_flags = SA_SIGINFO;
1682 fprintf(stderr, "gallium_hud: invalid signal %u\n", signo);
1683 else if (sigaction(signo, &action, NULL) < 0)
1684 fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo);
1691 hud_parse_env_var(hud, env);
1696 hud_destroy(struct hud_context *hud)
1698 struct pipe_context *pipe = hud->pipe;
1699 struct hud_pane *pane, *pane_tmp;
1700 struct hud_graph *graph, *graph_tmp;
1702 LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) {
1703 LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) {
1704 LIST_DEL(&graph->head);
1705 hud_graph_destroy(graph);
1707 LIST_DEL(&pane->head);
1711 hud_batch_query_cleanup(&hud->batch_query);
1712 pipe->delete_fs_state(pipe, hud->fs_color);
1713 pipe->delete_fs_state(pipe, hud->fs_text);
1714 pipe->delete_vs_state(pipe, hud->vs);
1715 pipe_sampler_view_reference(&hud->font_sampler_view, NULL);
1716 pipe_resource_reference(&hud->font.texture, NULL);