Home | History | Annotate | Download | only in hud
      1 /**************************************************************************
      2  *
      3  * Copyright 2013 Marek Olk <maraeo (at) gmail.com>
      4  * All Rights Reserved.
      5  *
      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:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     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.
     25  *
     26  **************************************************************************/
     27 
     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.
     31  *
     32  * The HUD is controlled with the GALLIUM_HUD environment variable.
     33  * Set GALLIUM_HUD=help for more info.
     34  */
     35 
     36 #include <inttypes.h>
     37 #include <signal.h>
     38 #include <stdio.h>
     39 
     40 #include "hud/hud_context.h"
     41 #include "hud/hud_private.h"
     42 
     43 #include "cso_cache/cso_context.h"
     44 #include "util/u_draw_quad.h"
     45 #include "util/u_format.h"
     46 #include "util/u_inlines.h"
     47 #include "util/u_memory.h"
     48 #include "util/u_math.h"
     49 #include "util/u_sampler.h"
     50 #include "util/u_simple_shaders.h"
     51 #include "util/u_string.h"
     52 #include "util/u_upload_mgr.h"
     53 #include "tgsi/tgsi_text.h"
     54 #include "tgsi/tgsi_dump.h"
     55 
     56 /* Control the visibility of all HUD contexts */
     57 static boolean huds_visible = TRUE;
     58 
     59 
     60 #ifdef PIPE_OS_UNIX
     61 static void
     62 signal_visible_handler(int sig, siginfo_t *siginfo, void *context)
     63 {
     64    huds_visible = !huds_visible;
     65 }
     66 #endif
     67 
     68 static void
     69 hud_draw_colored_prims(struct hud_context *hud, unsigned prim,
     70                        float *buffer, unsigned num_vertices,
     71                        float r, float g, float b, float a,
     72                        int xoffset, int yoffset, float yscale)
     73 {
     74    struct cso_context *cso = hud->cso;
     75    unsigned size = num_vertices * hud->color_prims.vbuf.stride;
     76 
     77    /* If a recording context is inactive, don't draw anything. */
     78    if (size > hud->color_prims.buffer_size)
     79       return;
     80 
     81    memcpy(hud->color_prims.vertices, buffer, size);
     82 
     83    hud->constants.color[0] = r;
     84    hud->constants.color[1] = g;
     85    hud->constants.color[2] = b;
     86    hud->constants.color[3] = a;
     87    hud->constants.translate[0] = (float) xoffset;
     88    hud->constants.translate[1] = (float) yoffset;
     89    hud->constants.scale[0] = 1;
     90    hud->constants.scale[1] = yscale;
     91    cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
     92 
     93    cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso),
     94                           1, &hud->color_prims.vbuf);
     95    cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
     96    cso_draw_arrays(cso, prim, 0, num_vertices);
     97 
     98    hud->color_prims.vertices += size / sizeof(float);
     99    hud->color_prims.vbuf.buffer_offset += size;
    100    hud->color_prims.buffer_size -= size;
    101 }
    102 
    103 static void
    104 hud_draw_colored_quad(struct hud_context *hud, unsigned prim,
    105                       unsigned x1, unsigned y1, unsigned x2, unsigned y2,
    106                       float r, float g, float b, float a)
    107 {
    108    float buffer[] = {
    109       (float) x1, (float) y1,
    110       (float) x1, (float) y2,
    111       (float) x2, (float) y2,
    112       (float) x2, (float) y1,
    113    };
    114 
    115    hud_draw_colored_prims(hud, prim, buffer, 4, r, g, b, a, 0, 0, 1);
    116 }
    117 
    118 static void
    119 hud_draw_background_quad(struct hud_context *hud,
    120                          unsigned x1, unsigned y1, unsigned x2, unsigned y2)
    121 {
    122    float *vertices = hud->bg.vertices + hud->bg.num_vertices*2;
    123    unsigned num = 0;
    124 
    125    assert(hud->bg.num_vertices + 4 <= hud->bg.max_num_vertices);
    126 
    127    vertices[num++] = (float) x1;
    128    vertices[num++] = (float) y1;
    129 
    130    vertices[num++] = (float) x1;
    131    vertices[num++] = (float) y2;
    132 
    133    vertices[num++] = (float) x2;
    134    vertices[num++] = (float) y2;
    135 
    136    vertices[num++] = (float) x2;
    137    vertices[num++] = (float) y1;
    138 
    139    hud->bg.num_vertices += num/2;
    140 }
    141 
    142 static void
    143 hud_draw_string(struct hud_context *hud, unsigned x, unsigned y,
    144                 const char *str, ...)
    145 {
    146    char buf[256];
    147    char *s = buf;
    148    float *vertices = hud->text.vertices + hud->text.num_vertices*4;
    149    unsigned num = 0;
    150 
    151    va_list ap;
    152    va_start(ap, str);
    153    util_vsnprintf(buf, sizeof(buf), str, ap);
    154    va_end(ap);
    155 
    156    if (!*s)
    157       return;
    158 
    159    hud_draw_background_quad(hud,
    160                             x, y,
    161                             x + strlen(buf)*hud->font.glyph_width,
    162                             y + hud->font.glyph_height);
    163 
    164    while (*s) {
    165       unsigned x1 = x;
    166       unsigned y1 = y;
    167       unsigned x2 = x + hud->font.glyph_width;
    168       unsigned y2 = y + hud->font.glyph_height;
    169       unsigned tx1 = (*s % 16) * hud->font.glyph_width;
    170       unsigned ty1 = (*s / 16) * hud->font.glyph_height;
    171       unsigned tx2 = tx1 + hud->font.glyph_width;
    172       unsigned ty2 = ty1 + hud->font.glyph_height;
    173 
    174       if (*s == ' ') {
    175          x += hud->font.glyph_width;
    176          s++;
    177          continue;
    178       }
    179 
    180       assert(hud->text.num_vertices + num/4 + 4 <= hud->text.max_num_vertices);
    181 
    182       vertices[num++] = (float) x1;
    183       vertices[num++] = (float) y1;
    184       vertices[num++] = (float) tx1;
    185       vertices[num++] = (float) ty1;
    186 
    187       vertices[num++] = (float) x1;
    188       vertices[num++] = (float) y2;
    189       vertices[num++] = (float) tx1;
    190       vertices[num++] = (float) ty2;
    191 
    192       vertices[num++] = (float) x2;
    193       vertices[num++] = (float) y2;
    194       vertices[num++] = (float) tx2;
    195       vertices[num++] = (float) ty2;
    196 
    197       vertices[num++] = (float) x2;
    198       vertices[num++] = (float) y1;
    199       vertices[num++] = (float) tx2;
    200       vertices[num++] = (float) ty1;
    201 
    202       x += hud->font.glyph_width;
    203       s++;
    204    }
    205 
    206    hud->text.num_vertices += num/4;
    207 }
    208 
    209 static void
    210 number_to_human_readable(double num, enum pipe_driver_query_type type,
    211                          char *out)
    212 {
    213    static const char *byte_units[] =
    214       {" B", " KB", " MB", " GB", " TB", " PB", " EB"};
    215    static const char *metric_units[] =
    216       {"", " k", " M", " G", " T", " P", " E"};
    217    static const char *time_units[] =
    218       {" us", " ms", " s"};  /* based on microseconds */
    219    static const char *hz_units[] =
    220       {" Hz", " KHz", " MHz", " GHz"};
    221    static const char *percent_units[] = {"%"};
    222    static const char *dbm_units[] = {" (-dBm)"};
    223    static const char *temperature_units[] = {" C"};
    224    static const char *volt_units[] = {" mV", " V"};
    225    static const char *amp_units[] = {" mA", " A"};
    226    static const char *watt_units[] = {" mW", " W"};
    227    static const char *float_units[] = {""};
    228 
    229    const char **units;
    230    unsigned max_unit;
    231    double divisor = (type == PIPE_DRIVER_QUERY_TYPE_BYTES) ? 1024 : 1000;
    232    unsigned unit = 0;
    233    double d = num;
    234 
    235    switch (type) {
    236    case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS:
    237       max_unit = ARRAY_SIZE(time_units)-1;
    238       units = time_units;
    239       break;
    240    case PIPE_DRIVER_QUERY_TYPE_VOLTS:
    241       max_unit = ARRAY_SIZE(volt_units)-1;
    242       units = volt_units;
    243       break;
    244    case PIPE_DRIVER_QUERY_TYPE_AMPS:
    245       max_unit = ARRAY_SIZE(amp_units)-1;
    246       units = amp_units;
    247       break;
    248    case PIPE_DRIVER_QUERY_TYPE_DBM:
    249       max_unit = ARRAY_SIZE(dbm_units)-1;
    250       units = dbm_units;
    251       break;
    252    case PIPE_DRIVER_QUERY_TYPE_TEMPERATURE:
    253       max_unit = ARRAY_SIZE(temperature_units)-1;
    254       units = temperature_units;
    255       break;
    256    case PIPE_DRIVER_QUERY_TYPE_FLOAT:
    257       max_unit = ARRAY_SIZE(float_units)-1;
    258       units = float_units;
    259       break;
    260    case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE:
    261       max_unit = ARRAY_SIZE(percent_units)-1;
    262       units = percent_units;
    263       break;
    264    case PIPE_DRIVER_QUERY_TYPE_BYTES:
    265       max_unit = ARRAY_SIZE(byte_units)-1;
    266       units = byte_units;
    267       break;
    268    case PIPE_DRIVER_QUERY_TYPE_HZ:
    269       max_unit = ARRAY_SIZE(hz_units)-1;
    270       units = hz_units;
    271       break;
    272    case PIPE_DRIVER_QUERY_TYPE_WATTS:
    273       max_unit = ARRAY_SIZE(watt_units)-1;
    274       units = watt_units;
    275       break;
    276    default:
    277       max_unit = ARRAY_SIZE(metric_units)-1;
    278       units = metric_units;
    279    }
    280 
    281    while (d > divisor && unit < max_unit) {
    282       d /= divisor;
    283       unit++;
    284    }
    285 
    286    /* Round to 3 decimal places so as not to print trailing zeros. */
    287    if (d*1000 != (int)(d*1000))
    288       d = round(d * 1000) / 1000;
    289 
    290    /* Show at least 4 digits with at most 3 decimal places, but not zeros. */
    291    if (d >= 1000 || d == (int)d)
    292       sprintf(out, "%.0f%s", d, units[unit]);
    293    else if (d >= 100 || d*10 == (int)(d*10))
    294       sprintf(out, "%.1f%s", d, units[unit]);
    295    else if (d >= 10 || d*100 == (int)(d*100))
    296       sprintf(out, "%.2f%s", d, units[unit]);
    297    else
    298       sprintf(out, "%.3f%s", d, units[unit]);
    299 }
    300 
    301 static void
    302 hud_draw_graph_line_strip(struct hud_context *hud, const struct hud_graph *gr,
    303                           unsigned xoffset, unsigned yoffset, float yscale)
    304 {
    305    if (gr->num_vertices <= 1)
    306       return;
    307 
    308    assert(gr->index <= gr->num_vertices);
    309 
    310    hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP,
    311                           gr->vertices, gr->index,
    312                           gr->color[0], gr->color[1], gr->color[2], 1,
    313                           xoffset + (gr->pane->max_num_vertices - gr->index - 1) * 2 - 1,
    314                           yoffset, yscale);
    315 
    316    if (gr->num_vertices <= gr->index)
    317       return;
    318 
    319    hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP,
    320                           gr->vertices + gr->index*2,
    321                           gr->num_vertices - gr->index,
    322                           gr->color[0], gr->color[1], gr->color[2], 1,
    323                           xoffset - gr->index*2 - 1, yoffset, yscale);
    324 }
    325 
    326 static void
    327 hud_pane_accumulate_vertices(struct hud_context *hud,
    328                              const struct hud_pane *pane)
    329 {
    330    struct hud_graph *gr;
    331    float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2;
    332    unsigned i, num = 0;
    333    char str[32];
    334    const unsigned last_line = pane->last_line;
    335 
    336    /* draw background */
    337    hud_draw_background_quad(hud,
    338                             pane->x1, pane->y1,
    339                             pane->x2, pane->y2);
    340 
    341    /* draw numbers on the right-hand side */
    342    for (i = 0; i <= last_line; i++) {
    343       unsigned x = pane->x2 + 2;
    344       unsigned y = pane->inner_y1 +
    345                    pane->inner_height * (last_line - i) / last_line -
    346                    hud->font.glyph_height / 2;
    347 
    348       number_to_human_readable(pane->max_value * i / last_line,
    349                                pane->type, str);
    350       hud_draw_string(hud, x, y, "%s", str);
    351    }
    352 
    353    /* draw info below the pane */
    354    i = 0;
    355    LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
    356       unsigned x = pane->x1 + 2;
    357       unsigned y = pane->y2 + 2 + i*hud->font.glyph_height;
    358 
    359       number_to_human_readable(gr->current_value, pane->type, str);
    360       hud_draw_string(hud, x, y, "  %s: %s", gr->name, str);
    361       i++;
    362    }
    363 
    364    /* draw border */
    365    assert(hud->whitelines.num_vertices + num/2 + 8 <= hud->whitelines.max_num_vertices);
    366    line_verts[num++] = (float) pane->x1;
    367    line_verts[num++] = (float) pane->y1;
    368    line_verts[num++] = (float) pane->x2;
    369    line_verts[num++] = (float) pane->y1;
    370 
    371    line_verts[num++] = (float) pane->x2;
    372    line_verts[num++] = (float) pane->y1;
    373    line_verts[num++] = (float) pane->x2;
    374    line_verts[num++] = (float) pane->y2;
    375 
    376    line_verts[num++] = (float) pane->x1;
    377    line_verts[num++] = (float) pane->y2;
    378    line_verts[num++] = (float) pane->x2;
    379    line_verts[num++] = (float) pane->y2;
    380 
    381    line_verts[num++] = (float) pane->x1;
    382    line_verts[num++] = (float) pane->y1;
    383    line_verts[num++] = (float) pane->x1;
    384    line_verts[num++] = (float) pane->y2;
    385 
    386    /* draw horizontal lines inside the graph */
    387    for (i = 0; i <= last_line; i++) {
    388       float y = round((pane->max_value * i / (double)last_line) *
    389                       pane->yscale + pane->inner_y2);
    390 
    391       assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices);
    392       line_verts[num++] = pane->x1;
    393       line_verts[num++] = y;
    394       line_verts[num++] = pane->x2;
    395       line_verts[num++] = y;
    396    }
    397 
    398    hud->whitelines.num_vertices += num/2;
    399 }
    400 
    401 static void
    402 hud_pane_draw_colored_objects(struct hud_context *hud,
    403                               const struct hud_pane *pane)
    404 {
    405    struct hud_graph *gr;
    406    unsigned i;
    407 
    408    /* draw colored quads below the pane */
    409    i = 0;
    410    LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
    411       unsigned x = pane->x1 + 2;
    412       unsigned y = pane->y2 + 2 + i*hud->font.glyph_height;
    413 
    414       hud_draw_colored_quad(hud, PIPE_PRIM_QUADS, x + 1, y + 1, x + 12, y + 13,
    415                             gr->color[0], gr->color[1], gr->color[2], 1);
    416       i++;
    417    }
    418 
    419    /* draw the line strips */
    420    LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
    421       hud_draw_graph_line_strip(hud, gr, pane->inner_x1, pane->inner_y2, pane->yscale);
    422    }
    423 }
    424 
    425 static void
    426 hud_prepare_vertices(struct hud_context *hud, struct vertex_queue *v,
    427                      unsigned num_vertices, unsigned stride)
    428 {
    429    v->num_vertices = 0;
    430    v->max_num_vertices = num_vertices;
    431    v->vbuf.stride = stride;
    432    v->buffer_size = stride * num_vertices;
    433 }
    434 
    435 /**
    436  * Draw the HUD to the texture \p tex.
    437  * The texture is usually the back buffer being displayed.
    438  */
    439 static void
    440 hud_draw_results(struct hud_context *hud, struct pipe_resource *tex)
    441 {
    442    struct cso_context *cso = hud->cso;
    443    struct pipe_context *pipe = hud->pipe;
    444    struct pipe_framebuffer_state fb;
    445    struct pipe_surface surf_templ, *surf;
    446    struct pipe_viewport_state viewport;
    447    const struct pipe_sampler_state *sampler_states[] =
    448          { &hud->font_sampler_state };
    449    struct hud_pane *pane;
    450 
    451    if (!huds_visible)
    452       return;
    453 
    454    hud->fb_width = tex->width0;
    455    hud->fb_height = tex->height0;
    456    hud->constants.two_div_fb_width = 2.0f / hud->fb_width;
    457    hud->constants.two_div_fb_height = 2.0f / hud->fb_height;
    458 
    459    cso_save_state(cso, (CSO_BIT_FRAMEBUFFER |
    460                         CSO_BIT_SAMPLE_MASK |
    461                         CSO_BIT_MIN_SAMPLES |
    462                         CSO_BIT_BLEND |
    463                         CSO_BIT_DEPTH_STENCIL_ALPHA |
    464                         CSO_BIT_FRAGMENT_SHADER |
    465                         CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
    466                         CSO_BIT_FRAGMENT_SAMPLERS |
    467                         CSO_BIT_RASTERIZER |
    468                         CSO_BIT_VIEWPORT |
    469                         CSO_BIT_STREAM_OUTPUTS |
    470                         CSO_BIT_GEOMETRY_SHADER |
    471                         CSO_BIT_TESSCTRL_SHADER |
    472                         CSO_BIT_TESSEVAL_SHADER |
    473                         CSO_BIT_VERTEX_SHADER |
    474                         CSO_BIT_VERTEX_ELEMENTS |
    475                         CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
    476                         CSO_BIT_PAUSE_QUERIES |
    477                         CSO_BIT_RENDER_CONDITION));
    478    cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
    479 
    480    /* set states */
    481    memset(&surf_templ, 0, sizeof(surf_templ));
    482    surf_templ.format = tex->format;
    483 
    484    /* Without this, AA lines look thinner if they are between 2 pixels
    485     * because the alpha is 0.5 on both pixels. (it's ugly)
    486     *
    487     * sRGB makes the width of all AA lines look the same.
    488     */
    489    if (hud->has_srgb) {
    490       enum pipe_format srgb_format = util_format_srgb(tex->format);
    491 
    492       if (srgb_format != PIPE_FORMAT_NONE)
    493          surf_templ.format = srgb_format;
    494    }
    495    surf = pipe->create_surface(pipe, tex, &surf_templ);
    496 
    497    memset(&fb, 0, sizeof(fb));
    498    fb.nr_cbufs = 1;
    499    fb.cbufs[0] = surf;
    500    fb.zsbuf = NULL;
    501    fb.width = hud->fb_width;
    502    fb.height = hud->fb_height;
    503 
    504    viewport.scale[0] = 0.5f * hud->fb_width;
    505    viewport.scale[1] = 0.5f * hud->fb_height;
    506    viewport.scale[2] = 1.0f;
    507    viewport.translate[0] = 0.5f * hud->fb_width;
    508    viewport.translate[1] = 0.5f * hud->fb_height;
    509    viewport.translate[2] = 0.0f;
    510 
    511    cso_set_framebuffer(cso, &fb);
    512    cso_set_sample_mask(cso, ~0);
    513    cso_set_min_samples(cso, 1);
    514    cso_set_depth_stencil_alpha(cso, &hud->dsa);
    515    cso_set_rasterizer(cso, &hud->rasterizer);
    516    cso_set_viewport(cso, &viewport);
    517    cso_set_stream_outputs(cso, 0, NULL, NULL);
    518    cso_set_tessctrl_shader_handle(cso, NULL);
    519    cso_set_tesseval_shader_handle(cso, NULL);
    520    cso_set_geometry_shader_handle(cso, NULL);
    521    cso_set_vertex_shader_handle(cso, hud->vs);
    522    cso_set_vertex_elements(cso, 2, hud->velems);
    523    cso_set_render_condition(cso, NULL, FALSE, 0);
    524    cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1,
    525                          &hud->font_sampler_view);
    526    cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states);
    527    cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
    528 
    529    /* draw accumulated vertices for background quads */
    530    cso_set_blend(cso, &hud->alpha_blend);
    531    cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
    532 
    533    if (hud->bg.num_vertices) {
    534       hud->constants.color[0] = 0;
    535       hud->constants.color[1] = 0;
    536       hud->constants.color[2] = 0;
    537       hud->constants.color[3] = 0.666f;
    538       hud->constants.translate[0] = 0;
    539       hud->constants.translate[1] = 0;
    540       hud->constants.scale[0] = 1;
    541       hud->constants.scale[1] = 1;
    542 
    543       cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
    544       cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
    545                              &hud->bg.vbuf);
    546       cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices);
    547    }
    548    pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL);
    549 
    550    /* draw accumulated vertices for white lines */
    551    cso_set_blend(cso, &hud->no_blend);
    552 
    553    hud->constants.color[0] = 1;
    554    hud->constants.color[1] = 1;
    555    hud->constants.color[2] = 1;
    556    hud->constants.color[3] = 1;
    557    hud->constants.translate[0] = 0;
    558    hud->constants.translate[1] = 0;
    559    hud->constants.scale[0] = 1;
    560    hud->constants.scale[1] = 1;
    561    cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
    562 
    563    if (hud->whitelines.num_vertices) {
    564       cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
    565                              &hud->whitelines.vbuf);
    566       cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
    567       cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices);
    568    }
    569    pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL);
    570 
    571    /* draw accumulated vertices for text */
    572    cso_set_blend(cso, &hud->alpha_blend);
    573    if (hud->text.num_vertices) {
    574       cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
    575                              &hud->text.vbuf);
    576       cso_set_fragment_shader_handle(hud->cso, hud->fs_text);
    577       cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices);
    578    }
    579    pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL);
    580 
    581    /* draw the rest */
    582    cso_set_rasterizer(cso, &hud->rasterizer_aa_lines);
    583    LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
    584       if (pane)
    585          hud_pane_draw_colored_objects(hud, pane);
    586    }
    587 
    588    cso_restore_state(cso);
    589    cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
    590 
    591    pipe_surface_reference(&surf, NULL);
    592 }
    593 
    594 static void
    595 hud_start_queries(struct hud_context *hud, struct pipe_context *pipe)
    596 {
    597    struct hud_pane *pane;
    598    struct hud_graph *gr;
    599 
    600    /* Start queries. */
    601    hud_batch_query_begin(hud->batch_query, pipe);
    602 
    603    LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
    604       LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
    605          if (gr->begin_query)
    606             gr->begin_query(gr, pipe);
    607       }
    608    }
    609 }
    610 
    611 /* Stop queries, query results, and record vertices for charts. */
    612 static void
    613 hud_stop_queries(struct hud_context *hud, struct pipe_context *pipe)
    614 {
    615    struct hud_pane *pane;
    616    struct hud_graph *gr, *next;
    617 
    618    /* prepare vertex buffers */
    619    hud_prepare_vertices(hud, &hud->bg, 16 * 256, 2 * sizeof(float));
    620    hud_prepare_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float));
    621    hud_prepare_vertices(hud, &hud->text, 16 * 1024, 4 * sizeof(float));
    622    hud_prepare_vertices(hud, &hud->color_prims, 32 * 1024, 2 * sizeof(float));
    623 
    624    /* Allocate everything once and divide the storage into 3 portions
    625     * manually, because u_upload_alloc can unmap memory from previous calls.
    626     */
    627    u_upload_alloc(pipe->stream_uploader, 0,
    628                   hud->bg.buffer_size +
    629                   hud->whitelines.buffer_size +
    630                   hud->text.buffer_size +
    631                   hud->color_prims.buffer_size,
    632                   16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource,
    633                   (void**)&hud->bg.vertices);
    634    if (!hud->bg.vertices)
    635       return;
    636 
    637    pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
    638    pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
    639    pipe_resource_reference(&hud->color_prims.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
    640 
    641    hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset +
    642                                         hud->bg.buffer_size;
    643    hud->whitelines.vertices = hud->bg.vertices +
    644                               hud->bg.buffer_size / sizeof(float);
    645 
    646    hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset +
    647                                   hud->whitelines.buffer_size;
    648    hud->text.vertices = hud->whitelines.vertices +
    649                         hud->whitelines.buffer_size / sizeof(float);
    650 
    651    hud->color_prims.vbuf.buffer_offset = hud->text.vbuf.buffer_offset +
    652                                          hud->text.buffer_size;
    653    hud->color_prims.vertices = hud->text.vertices +
    654                                hud->text.buffer_size / sizeof(float);
    655 
    656    /* prepare all graphs */
    657    hud_batch_query_update(hud->batch_query, pipe);
    658 
    659    LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
    660       LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
    661          gr->query_new_value(gr, pipe);
    662       }
    663 
    664       if (pane->sort_items) {
    665          LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) {
    666             /* ignore the last one */
    667             if (&gr->head == pane->graph_list.prev)
    668                continue;
    669 
    670             /* This is an incremental bubble sort, because we only do one pass
    671              * per frame. It will eventually reach an equilibrium.
    672              */
    673             if (gr->current_value <
    674                 LIST_ENTRY(struct hud_graph, next, head)->current_value) {
    675                LIST_DEL(&gr->head);
    676                LIST_ADD(&gr->head, &next->head);
    677             }
    678          }
    679       }
    680 
    681       hud_pane_accumulate_vertices(hud, pane);
    682    }
    683 
    684    /* unmap the uploader's vertex buffer before drawing */
    685    u_upload_unmap(pipe->stream_uploader);
    686 }
    687 
    688 /**
    689  * Record queries and draw the HUD. The "cso" parameter acts as a filter.
    690  * If "cso" is not the recording context, recording is skipped.
    691  * If "cso" is not the drawing context, drawing is skipped.
    692  * cso == NULL ignores the filter.
    693  */
    694 void
    695 hud_run(struct hud_context *hud, struct cso_context *cso,
    696         struct pipe_resource *tex)
    697 {
    698    struct pipe_context *pipe = cso ? cso_get_pipe_context(cso) : NULL;
    699 
    700    /* If "cso" is the recording or drawing context or NULL, execute
    701     * the operation. Otherwise, don't do anything.
    702     */
    703    if (hud->record_pipe && (!pipe || pipe == hud->record_pipe))
    704       hud_stop_queries(hud, hud->record_pipe);
    705 
    706    if (hud->cso && (!cso || cso == hud->cso))
    707       hud_draw_results(hud, tex);
    708 
    709    if (hud->record_pipe && (!pipe || pipe == hud->record_pipe))
    710       hud_start_queries(hud, hud->record_pipe);
    711 }
    712 
    713 /**
    714  * Record query results and assemble vertices if "pipe" is a recording but
    715  * not drawing context.
    716  */
    717 void
    718 hud_record_only(struct hud_context *hud, struct pipe_context *pipe)
    719 {
    720    assert(pipe);
    721 
    722    /* If it's a drawing context, only hud_run() records query results. */
    723    if (pipe == hud->pipe || pipe != hud->record_pipe)
    724       return;
    725 
    726    hud_stop_queries(hud, hud->record_pipe);
    727    hud_start_queries(hud, hud->record_pipe);
    728 }
    729 
    730 static void
    731 fixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10)
    732 {
    733    if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0)
    734       *exp10 = (*exp10 / 1000) * 1024;
    735 }
    736 
    737 /**
    738  * Set the maximum value for the Y axis of the graph.
    739  * This scales the graph accordingly.
    740  */
    741 void
    742 hud_pane_set_max_value(struct hud_pane *pane, uint64_t value)
    743 {
    744    double leftmost_digit;
    745    uint64_t exp10;
    746    int i;
    747 
    748    /* The following code determines the max_value in the graph as well as
    749     * how many describing lines are drawn. The max_value is rounded up,
    750     * so that all drawn numbers are rounded for readability.
    751     * We want to print multiples of a simple number instead of multiples of
    752     * hard-to-read numbers like 1.753.
    753     */
    754 
    755    /* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't
    756     * overflow. (11 is safe) */
    757    exp10 = 1;
    758    for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) {
    759       exp10 *= 10;
    760       fixup_bytes(pane->type, i + 1, &exp10);
    761    }
    762 
    763    leftmost_digit = DIV_ROUND_UP(value, exp10);
    764 
    765    /* Round 9 to 10. */
    766    if (leftmost_digit == 9) {
    767       leftmost_digit = 1;
    768       exp10 *= 10;
    769       fixup_bytes(pane->type, i + 1, &exp10);
    770    }
    771 
    772    switch ((unsigned)leftmost_digit) {
    773    case 1:
    774       pane->last_line = 5; /* lines in +1/5 increments */
    775       break;
    776    case 2:
    777       pane->last_line = 8; /* lines in +1/4 increments. */
    778       break;
    779    case 3:
    780    case 4:
    781       pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments */
    782       break;
    783    case 5:
    784    case 6:
    785    case 7:
    786    case 8:
    787       pane->last_line = leftmost_digit; /* lines in +1 increments */
    788       break;
    789    default:
    790       assert(0);
    791    }
    792 
    793    /* Truncate {3,4} to {2.5, 3.5} if possible. */
    794    for (i = 3; i <= 4; i++) {
    795       if (leftmost_digit == i && value <= (i - 0.5) * exp10) {
    796          leftmost_digit = i - 0.5;
    797          pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments. */
    798       }
    799    }
    800 
    801    /* Truncate 2 to a multiple of 0.2 in (1, 1.6] if possible. */
    802    if (leftmost_digit == 2) {
    803       for (i = 1; i <= 3; i++) {
    804          if (value <= (1 + i*0.2) * exp10) {
    805             leftmost_digit = 1 + i*0.2;
    806             pane->last_line = 5 + i; /* lines in +1/5 increments. */
    807             break;
    808          }
    809       }
    810    }
    811 
    812    pane->max_value = leftmost_digit * exp10;
    813    pane->yscale = -(int)pane->inner_height / (float)pane->max_value;
    814 }
    815 
    816 static void
    817 hud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane)
    818 {
    819    unsigned i;
    820    float tmp = 0.0f;
    821 
    822    if (pane->dyn_ceil_last_ran != gr->index) {
    823       LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
    824          for (i = 0; i <  gr->num_vertices; ++i) {
    825             tmp = gr->vertices[i * 2 + 1] > tmp ?
    826                   gr->vertices[i * 2 + 1] : tmp;
    827          }
    828       }
    829 
    830       /* Avoid setting it lower than the initial starting height. */
    831       tmp = tmp > pane->initial_max_value ? tmp : pane->initial_max_value;
    832       hud_pane_set_max_value(pane, tmp);
    833    }
    834 
    835    /*
    836     * Mark this adjustment run so we could avoid repeating a full update
    837     * again needlessly in case the pane has more than one graph.
    838     */
    839    pane->dyn_ceil_last_ran = gr->index;
    840 }
    841 
    842 static struct hud_pane *
    843 hud_pane_create(struct hud_context *hud,
    844                 unsigned x1, unsigned y1, unsigned x2, unsigned y2,
    845                 unsigned period, uint64_t max_value, uint64_t ceiling,
    846                 boolean dyn_ceiling, boolean sort_items)
    847 {
    848    struct hud_pane *pane = CALLOC_STRUCT(hud_pane);
    849 
    850    if (!pane)
    851       return NULL;
    852 
    853    pane->hud = hud;
    854    pane->x1 = x1;
    855    pane->y1 = y1;
    856    pane->x2 = x2;
    857    pane->y2 = y2;
    858    pane->inner_x1 = x1 + 1;
    859    pane->inner_x2 = x2 - 1;
    860    pane->inner_y1 = y1 + 1;
    861    pane->inner_y2 = y2 - 1;
    862    pane->inner_width = pane->inner_x2 - pane->inner_x1;
    863    pane->inner_height = pane->inner_y2 - pane->inner_y1;
    864    pane->period = period;
    865    pane->max_num_vertices = (x2 - x1 + 2) / 2;
    866    pane->ceiling = ceiling;
    867    pane->dyn_ceiling = dyn_ceiling;
    868    pane->dyn_ceil_last_ran = 0;
    869    pane->sort_items = sort_items;
    870    pane->initial_max_value = max_value;
    871    hud_pane_set_max_value(pane, max_value);
    872    LIST_INITHEAD(&pane->graph_list);
    873    return pane;
    874 }
    875 
    876 /* replace '-' with a space */
    877 static void
    878 strip_hyphens(char *s)
    879 {
    880    while (*s) {
    881       if (*s == '-')
    882          *s = ' ';
    883       s++;
    884    }
    885 }
    886 
    887 /**
    888  * Add a graph to an existing pane.
    889  * One pane can contain multiple graphs over each other.
    890  */
    891 void
    892 hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr)
    893 {
    894    static const float colors[][3] = {
    895       {0, 1, 0},
    896       {1, 0, 0},
    897       {0, 1, 1},
    898       {1, 0, 1},
    899       {1, 1, 0},
    900       {0.5, 1, 0.5},
    901       {1, 0.5, 0.5},
    902       {0.5, 1, 1},
    903       {1, 0.5, 1},
    904       {1, 1, 0.5},
    905       {0, 0.5, 0},
    906       {0.5, 0, 0},
    907       {0, 0.5, 0.5},
    908       {0.5, 0, 0.5},
    909       {0.5, 0.5, 0},
    910    };
    911    unsigned color = pane->next_color % ARRAY_SIZE(colors);
    912 
    913    strip_hyphens(gr->name);
    914 
    915    gr->vertices = MALLOC(pane->max_num_vertices * sizeof(float) * 2);
    916    gr->color[0] = colors[color][0];
    917    gr->color[1] = colors[color][1];
    918    gr->color[2] = colors[color][2];
    919    gr->pane = pane;
    920    LIST_ADDTAIL(&gr->head, &pane->graph_list);
    921    pane->num_graphs++;
    922    pane->next_color++;
    923 }
    924 
    925 void
    926 hud_graph_add_value(struct hud_graph *gr, double value)
    927 {
    928    gr->current_value = value;
    929    value = value > gr->pane->ceiling ? gr->pane->ceiling : value;
    930 
    931    if (gr->fd) {
    932       if (fabs(value - lround(value)) > FLT_EPSILON) {
    933          fprintf(gr->fd, "%f\n", value);
    934       }
    935       else {
    936          fprintf(gr->fd, "%" PRIu64 "\n", (uint64_t) lround(value));
    937       }
    938    }
    939 
    940    if (gr->index == gr->pane->max_num_vertices) {
    941       gr->vertices[0] = 0;
    942       gr->vertices[1] = gr->vertices[(gr->index-1)*2+1];
    943       gr->index = 1;
    944    }
    945    gr->vertices[(gr->index)*2+0] = (float) (gr->index * 2);
    946    gr->vertices[(gr->index)*2+1] = (float) value;
    947    gr->index++;
    948 
    949    if (gr->num_vertices < gr->pane->max_num_vertices) {
    950       gr->num_vertices++;
    951    }
    952 
    953    if (gr->pane->dyn_ceiling == true) {
    954       hud_pane_update_dyn_ceiling(gr, gr->pane);
    955    }
    956    if (value > gr->pane->max_value) {
    957       hud_pane_set_max_value(gr->pane, value);
    958    }
    959 }
    960 
    961 static void
    962 hud_graph_destroy(struct hud_graph *graph, struct pipe_context *pipe)
    963 {
    964    FREE(graph->vertices);
    965    if (graph->free_query_data)
    966       graph->free_query_data(graph->query_data, pipe);
    967    if (graph->fd)
    968       fclose(graph->fd);
    969    FREE(graph);
    970 }
    971 
    972 static void strcat_without_spaces(char *dst, const char *src)
    973 {
    974    dst += strlen(dst);
    975    while (*src) {
    976       if (*src == ' ')
    977          *dst++ = '_';
    978       else
    979          *dst++ = *src;
    980       src++;
    981    }
    982    *dst = 0;
    983 }
    984 
    985 
    986 #ifdef PIPE_OS_WINDOWS
    987 #define W_OK 0
    988 static int
    989 access(const char *pathname, int mode)
    990 {
    991    /* no-op */
    992    return 0;
    993 }
    994 
    995 #define PATH_SEP "\\"
    996 
    997 #else
    998 
    999 #define PATH_SEP "/"
   1000 
   1001 #endif
   1002 
   1003 
   1004 /**
   1005  * If the GALLIUM_HUD_DUMP_DIR env var is set, we'll write the raw
   1006  * HUD values to files at ${GALLIUM_HUD_DUMP_DIR}/<stat> where <stat>
   1007  * is a HUD variable such as "fps", or "cpu"
   1008  */
   1009 static void
   1010 hud_graph_set_dump_file(struct hud_graph *gr)
   1011 {
   1012    const char *hud_dump_dir = getenv("GALLIUM_HUD_DUMP_DIR");
   1013 
   1014    if (hud_dump_dir && access(hud_dump_dir, W_OK) == 0) {
   1015       char *dump_file = malloc(strlen(hud_dump_dir) + sizeof(PATH_SEP)
   1016                                + sizeof(gr->name));
   1017       if (dump_file) {
   1018          strcpy(dump_file, hud_dump_dir);
   1019          strcat(dump_file, PATH_SEP);
   1020          strcat_without_spaces(dump_file, gr->name);
   1021          gr->fd = fopen(dump_file, "w+");
   1022          if (gr->fd) {
   1023             /* flush output after each line is written */
   1024             setvbuf(gr->fd, NULL, _IOLBF, 0);
   1025          }
   1026          free(dump_file);
   1027       }
   1028    }
   1029 }
   1030 
   1031 /**
   1032  * Read a string from the environment variable.
   1033  * The separators "+", ",", ":", and ";" terminate the string.
   1034  * Return the number of read characters.
   1035  */
   1036 static int
   1037 parse_string(const char *s, char *out)
   1038 {
   1039    int i;
   1040 
   1041    for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '=';
   1042         s++, out++, i++)
   1043       *out = *s;
   1044 
   1045    *out = 0;
   1046 
   1047    if (*s && !i) {
   1048       fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while "
   1049               "parsing a string\n", *s, *s);
   1050       fflush(stderr);
   1051    }
   1052 
   1053    return i;
   1054 }
   1055 
   1056 static char *
   1057 read_pane_settings(char *str, unsigned * const x, unsigned * const y,
   1058                unsigned * const width, unsigned * const height,
   1059                uint64_t * const ceiling, boolean * const dyn_ceiling,
   1060                boolean *reset_colors, boolean *sort_items)
   1061 {
   1062    char *ret = str;
   1063    unsigned tmp;
   1064 
   1065    while (*str == '.') {
   1066       ++str;
   1067       switch (*str) {
   1068       case 'x':
   1069          ++str;
   1070          *x = strtoul(str, &ret, 10);
   1071          str = ret;
   1072          break;
   1073 
   1074       case 'y':
   1075          ++str;
   1076          *y = strtoul(str, &ret, 10);
   1077          str = ret;
   1078          break;
   1079 
   1080       case 'w':
   1081          ++str;
   1082          tmp = strtoul(str, &ret, 10);
   1083          *width = tmp > 80 ? tmp : 80; /* 80 is chosen arbitrarily */
   1084          str = ret;
   1085          break;
   1086 
   1087       /*
   1088        * Prevent setting height to less than 50. If the height is set to less,
   1089        * the text of the Y axis labels on the graph will start overlapping.
   1090        */
   1091       case 'h':
   1092          ++str;
   1093          tmp = strtoul(str, &ret, 10);
   1094          *height = tmp > 50 ? tmp : 50;
   1095          str = ret;
   1096          break;
   1097 
   1098       case 'c':
   1099          ++str;
   1100          tmp = strtoul(str, &ret, 10);
   1101          *ceiling = tmp > 10 ? tmp : 10;
   1102          str = ret;
   1103          break;
   1104 
   1105       case 'd':
   1106          ++str;
   1107          ret = str;
   1108          *dyn_ceiling = true;
   1109          break;
   1110 
   1111       case 'r':
   1112          ++str;
   1113          ret = str;
   1114          *reset_colors = true;
   1115          break;
   1116 
   1117       case 's':
   1118          ++str;
   1119          ret = str;
   1120          *sort_items = true;
   1121          break;
   1122 
   1123       default:
   1124          fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *str);
   1125          fflush(stderr);
   1126       }
   1127 
   1128    }
   1129 
   1130    return ret;
   1131 }
   1132 
   1133 static boolean
   1134 has_occlusion_query(struct pipe_screen *screen)
   1135 {
   1136    return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) != 0;
   1137 }
   1138 
   1139 static boolean
   1140 has_streamout(struct pipe_screen *screen)
   1141 {
   1142    return screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0;
   1143 }
   1144 
   1145 static boolean
   1146 has_pipeline_stats_query(struct pipe_screen *screen)
   1147 {
   1148    return screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS) != 0;
   1149 }
   1150 
   1151 static void
   1152 hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
   1153                   const char *env)
   1154 {
   1155    unsigned num, i;
   1156    char name_a[256], s[256];
   1157    char *name;
   1158    struct hud_pane *pane = NULL;
   1159    unsigned x = 10, y = 10;
   1160    unsigned width = 251, height = 100;
   1161    unsigned period = 500 * 1000;  /* default period (1/2 second) */
   1162    uint64_t ceiling = UINT64_MAX;
   1163    unsigned column_width = 251;
   1164    boolean dyn_ceiling = false;
   1165    boolean reset_colors = false;
   1166    boolean sort_items = false;
   1167    const char *period_env;
   1168 
   1169    /*
   1170     * The GALLIUM_HUD_PERIOD env var sets the graph update rate.
   1171     * The env var is in seconds (a float).
   1172     * Zero means update after every frame.
   1173     */
   1174    period_env = getenv("GALLIUM_HUD_PERIOD");
   1175    if (period_env) {
   1176       float p = (float) atof(period_env);
   1177       if (p >= 0.0f) {
   1178          period = (unsigned) (p * 1000 * 1000);
   1179       }
   1180    }
   1181 
   1182    while ((num = parse_string(env, name_a)) != 0) {
   1183       env += num;
   1184 
   1185       /* check for explicit location, size and etc. settings */
   1186       name = read_pane_settings(name_a, &x, &y, &width, &height, &ceiling,
   1187                                 &dyn_ceiling, &reset_colors, &sort_items);
   1188 
   1189      /*
   1190       * Keep track of overall column width to avoid pane overlapping in case
   1191       * later we create a new column while the bottom pane in the current
   1192       * column is less wide than the rest of the panes in it.
   1193       */
   1194      column_width = width > column_width ? width : column_width;
   1195 
   1196       if (!pane) {
   1197          pane = hud_pane_create(hud, x, y, x + width, y + height, period, 10,
   1198                                 ceiling, dyn_ceiling, sort_items);
   1199          if (!pane)
   1200             return;
   1201       }
   1202 
   1203       if (reset_colors) {
   1204          pane->next_color = 0;
   1205          reset_colors = false;
   1206       }
   1207 
   1208       /* Add a graph. */
   1209 #if defined(HAVE_GALLIUM_EXTRA_HUD) || defined(HAVE_LIBSENSORS)
   1210       char arg_name[64];
   1211 #endif
   1212       /* IF YOU CHANGE THIS, UPDATE print_help! */
   1213       if (strcmp(name, "fps") == 0) {
   1214          hud_fps_graph_install(pane);
   1215       }
   1216       else if (strcmp(name, "cpu") == 0) {
   1217          hud_cpu_graph_install(pane, ALL_CPUS);
   1218       }
   1219       else if (sscanf(name, "cpu%u%s", &i, s) == 1) {
   1220          hud_cpu_graph_install(pane, i);
   1221       }
   1222       else if (strcmp(name, "API-thread-busy") == 0) {
   1223          hud_thread_busy_install(pane, name, false);
   1224       }
   1225       else if (strcmp(name, "API-thread-offloaded-slots") == 0) {
   1226          hud_thread_counter_install(pane, name, HUD_COUNTER_OFFLOADED);
   1227       }
   1228       else if (strcmp(name, "API-thread-direct-slots") == 0) {
   1229          hud_thread_counter_install(pane, name, HUD_COUNTER_DIRECT);
   1230       }
   1231       else if (strcmp(name, "API-thread-num-syncs") == 0) {
   1232          hud_thread_counter_install(pane, name, HUD_COUNTER_SYNCS);
   1233       }
   1234       else if (strcmp(name, "main-thread-busy") == 0) {
   1235          hud_thread_busy_install(pane, name, true);
   1236       }
   1237 #ifdef HAVE_GALLIUM_EXTRA_HUD
   1238       else if (sscanf(name, "nic-rx-%s", arg_name) == 1) {
   1239          hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX);
   1240       }
   1241       else if (sscanf(name, "nic-tx-%s", arg_name) == 1) {
   1242          hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_TX);
   1243       }
   1244       else if (sscanf(name, "nic-rssi-%s", arg_name) == 1) {
   1245          hud_nic_graph_install(pane, arg_name, NIC_RSSI_DBM);
   1246          pane->type = PIPE_DRIVER_QUERY_TYPE_DBM;
   1247       }
   1248       else if (sscanf(name, "diskstat-rd-%s", arg_name) == 1) {
   1249          hud_diskstat_graph_install(pane, arg_name, DISKSTAT_RD);
   1250          pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES;
   1251       }
   1252       else if (sscanf(name, "diskstat-wr-%s", arg_name) == 1) {
   1253          hud_diskstat_graph_install(pane, arg_name, DISKSTAT_WR);
   1254          pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES;
   1255       }
   1256       else if (sscanf(name, "cpufreq-min-cpu%u", &i) == 1) {
   1257          hud_cpufreq_graph_install(pane, i, CPUFREQ_MINIMUM);
   1258          pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
   1259       }
   1260       else if (sscanf(name, "cpufreq-cur-cpu%u", &i) == 1) {
   1261          hud_cpufreq_graph_install(pane, i, CPUFREQ_CURRENT);
   1262          pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
   1263       }
   1264       else if (sscanf(name, "cpufreq-max-cpu%u", &i) == 1) {
   1265          hud_cpufreq_graph_install(pane, i, CPUFREQ_MAXIMUM);
   1266          pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
   1267       }
   1268 #endif
   1269 #ifdef HAVE_LIBSENSORS
   1270       else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) {
   1271          hud_sensors_temp_graph_install(pane, arg_name,
   1272                                         SENSORS_TEMP_CURRENT);
   1273          pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE;
   1274       }
   1275       else if (sscanf(name, "sensors_temp_cr-%s", arg_name) == 1) {
   1276          hud_sensors_temp_graph_install(pane, arg_name,
   1277                                         SENSORS_TEMP_CRITICAL);
   1278          pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE;
   1279       }
   1280       else if (sscanf(name, "sensors_volt_cu-%s", arg_name) == 1) {
   1281          hud_sensors_temp_graph_install(pane, arg_name,
   1282                                         SENSORS_VOLTAGE_CURRENT);
   1283          pane->type = PIPE_DRIVER_QUERY_TYPE_VOLTS;
   1284       }
   1285       else if (sscanf(name, "sensors_curr_cu-%s", arg_name) == 1) {
   1286          hud_sensors_temp_graph_install(pane, arg_name,
   1287                                         SENSORS_CURRENT_CURRENT);
   1288          pane->type = PIPE_DRIVER_QUERY_TYPE_AMPS;
   1289       }
   1290       else if (sscanf(name, "sensors_pow_cu-%s", arg_name) == 1) {
   1291          hud_sensors_temp_graph_install(pane, arg_name,
   1292                                         SENSORS_POWER_CURRENT);
   1293          pane->type = PIPE_DRIVER_QUERY_TYPE_WATTS;
   1294       }
   1295 #endif
   1296       else if (strcmp(name, "samples-passed") == 0 &&
   1297                has_occlusion_query(screen)) {
   1298          hud_pipe_query_install(&hud->batch_query, pane,
   1299                                 "samples-passed",
   1300                                 PIPE_QUERY_OCCLUSION_COUNTER, 0, 0,
   1301                                 PIPE_DRIVER_QUERY_TYPE_UINT64,
   1302                                 PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
   1303                                 0);
   1304       }
   1305       else if (strcmp(name, "primitives-generated") == 0 &&
   1306                has_streamout(screen)) {
   1307          hud_pipe_query_install(&hud->batch_query, pane,
   1308                                 "primitives-generated",
   1309                                 PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0,
   1310                                 PIPE_DRIVER_QUERY_TYPE_UINT64,
   1311                                 PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
   1312                                 0);
   1313       }
   1314       else {
   1315          boolean processed = FALSE;
   1316 
   1317          /* pipeline statistics queries */
   1318          if (has_pipeline_stats_query(screen)) {
   1319             static const char *pipeline_statistics_names[] =
   1320             {
   1321                "ia-vertices",
   1322                "ia-primitives",
   1323                "vs-invocations",
   1324                "gs-invocations",
   1325                "gs-primitives",
   1326                "clipper-invocations",
   1327                "clipper-primitives-generated",
   1328                "ps-invocations",
   1329                "hs-invocations",
   1330                "ds-invocations",
   1331                "cs-invocations"
   1332             };
   1333             for (i = 0; i < ARRAY_SIZE(pipeline_statistics_names); ++i)
   1334                if (strcmp(name, pipeline_statistics_names[i]) == 0)
   1335                   break;
   1336             if (i < ARRAY_SIZE(pipeline_statistics_names)) {
   1337                hud_pipe_query_install(&hud->batch_query, pane, name,
   1338                                       PIPE_QUERY_PIPELINE_STATISTICS, i,
   1339                                       0, PIPE_DRIVER_QUERY_TYPE_UINT64,
   1340                                       PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
   1341                                       0);
   1342                processed = TRUE;
   1343             }
   1344          }
   1345 
   1346          /* driver queries */
   1347          if (!processed) {
   1348             if (!hud_driver_query_install(&hud->batch_query, pane,
   1349                                           screen, name)) {
   1350                fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name);
   1351                fflush(stderr);
   1352             }
   1353          }
   1354       }
   1355 
   1356       if (*env == ':') {
   1357          env++;
   1358 
   1359          if (!pane) {
   1360             fprintf(stderr, "gallium_hud: syntax error: unexpected ':', "
   1361                     "expected a name\n");
   1362             fflush(stderr);
   1363             break;
   1364          }
   1365 
   1366          num = parse_string(env, s);
   1367          env += num;
   1368 
   1369          if (num && sscanf(s, "%u", &i) == 1) {
   1370             hud_pane_set_max_value(pane, i);
   1371             pane->initial_max_value = i;
   1372          }
   1373          else {
   1374             fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) "
   1375                             "after ':'\n", *env, *env);
   1376             fflush(stderr);
   1377          }
   1378       }
   1379 
   1380       if (*env == '=') {
   1381          env++;
   1382 
   1383          if (!pane) {
   1384             fprintf(stderr, "gallium_hud: syntax error: unexpected '=', "
   1385                     "expected a name\n");
   1386             fflush(stderr);
   1387             break;
   1388          }
   1389 
   1390          num = parse_string(env, s);
   1391          env += num;
   1392 
   1393          strip_hyphens(s);
   1394          if (!LIST_IS_EMPTY(&pane->graph_list)) {
   1395             struct hud_graph *graph;
   1396             graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head);
   1397             strncpy(graph->name, s, sizeof(graph->name)-1);
   1398             graph->name[sizeof(graph->name)-1] = 0;
   1399          }
   1400       }
   1401 
   1402       if (*env == 0)
   1403          break;
   1404 
   1405       /* parse a separator */
   1406       switch (*env) {
   1407       case '+':
   1408          env++;
   1409          break;
   1410 
   1411       case ',':
   1412          env++;
   1413          if (!pane)
   1414             break;
   1415 
   1416          y += height + hud->font.glyph_height * (pane->num_graphs + 2);
   1417          height = 100;
   1418 
   1419          if (pane && pane->num_graphs) {
   1420             LIST_ADDTAIL(&pane->head, &hud->pane_list);
   1421             pane = NULL;
   1422          }
   1423          break;
   1424 
   1425       case ';':
   1426          env++;
   1427          y = 10;
   1428          x += column_width + hud->font.glyph_width * 9;
   1429          height = 100;
   1430 
   1431          if (pane && pane->num_graphs) {
   1432             LIST_ADDTAIL(&pane->head, &hud->pane_list);
   1433             pane = NULL;
   1434          }
   1435 
   1436          /* Starting a new column; reset column width. */
   1437          column_width = 251;
   1438          break;
   1439 
   1440       default:
   1441          fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env);
   1442          fflush(stderr);
   1443       }
   1444 
   1445       /* Reset to defaults for the next pane in case these were modified. */
   1446       width = 251;
   1447       ceiling = UINT64_MAX;
   1448       dyn_ceiling = false;
   1449       sort_items = false;
   1450 
   1451    }
   1452 
   1453    if (pane) {
   1454       if (pane->num_graphs) {
   1455          LIST_ADDTAIL(&pane->head, &hud->pane_list);
   1456       }
   1457       else {
   1458          FREE(pane);
   1459       }
   1460    }
   1461 
   1462    LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
   1463       struct hud_graph *gr;
   1464 
   1465       LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
   1466          hud_graph_set_dump_file(gr);
   1467       }
   1468    }
   1469 }
   1470 
   1471 static void
   1472 print_help(struct pipe_screen *screen)
   1473 {
   1474    int i, num_queries, num_cpus = hud_get_num_cpus();
   1475 
   1476    puts("Syntax: GALLIUM_HUD=name1[+name2][...][:value1][,nameI...][;nameJ...]");
   1477    puts("");
   1478    puts("  Names are identifiers of data sources which will be drawn as graphs");
   1479    puts("  in panes. Multiple graphs can be drawn in the same pane.");
   1480    puts("  There can be multiple panes placed in rows and columns.");
   1481    puts("");
   1482    puts("  '+' separates names which will share a pane.");
   1483    puts("  ':[value]' specifies the initial maximum value of the Y axis");
   1484    puts("             for the given pane.");
   1485    puts("  ',' creates a new pane below the last one.");
   1486    puts("  ';' creates a new pane at the top of the next column.");
   1487    puts("  '=' followed by a string, changes the name of the last data source");
   1488    puts("      to that string");
   1489    puts("");
   1490    puts("  Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\"");
   1491    puts("");
   1492    puts("  Additionally, by prepending '.[identifier][value]' modifiers to");
   1493    puts("  a name, it is possible to explicitly set the location and size");
   1494    puts("  of a pane, along with limiting overall maximum value of the");
   1495    puts("  Y axis and activating dynamic readjustment of the Y axis.");
   1496    puts("  Several modifiers may be applied to the same pane simultaneously.");
   1497    puts("");
   1498    puts("  'x[value]' sets the location of the pane on the x axis relative");
   1499    puts("             to the upper-left corner of the viewport, in pixels.");
   1500    puts("  'y[value]' sets the location of the pane on the y axis relative");
   1501    puts("             to the upper-left corner of the viewport, in pixels.");
   1502    puts("  'w[value]' sets width of the graph pixels.");
   1503    puts("  'h[value]' sets height of the graph in pixels.");
   1504    puts("  'c[value]' sets the ceiling of the value of the Y axis.");
   1505    puts("             If the graph needs to draw values higher than");
   1506    puts("             the ceiling allows, the value is clamped.");
   1507    puts("  'd' activates dynamic Y axis readjustment to set the value of");
   1508    puts("      the Y axis to match the highest value still visible in the graph.");
   1509    puts("  'r' resets the color counter (the next color will be green)");
   1510    puts("  's' sort items below graphs in descending order");
   1511    puts("");
   1512    puts("  If 'c' and 'd' modifiers are used simultaneously, both are in effect:");
   1513    puts("  the Y axis does not go above the restriction imposed by 'c' while");
   1514    puts("  still adjusting the value of the Y axis down when appropriate.");
   1515    puts("");
   1516    puts("  Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\"");
   1517    puts("");
   1518    puts("  Available names:");
   1519    puts("    fps");
   1520    puts("    cpu");
   1521 
   1522    for (i = 0; i < num_cpus; i++)
   1523       printf("    cpu%i\n", i);
   1524 
   1525    if (has_occlusion_query(screen))
   1526       puts("    samples-passed");
   1527    if (has_streamout(screen))
   1528       puts("    primitives-generated");
   1529 
   1530    if (has_pipeline_stats_query(screen)) {
   1531       puts("    ia-vertices");
   1532       puts("    ia-primitives");
   1533       puts("    vs-invocations");
   1534       puts("    gs-invocations");
   1535       puts("    gs-primitives");
   1536       puts("    clipper-invocations");
   1537       puts("    clipper-primitives-generated");
   1538       puts("    ps-invocations");
   1539       puts("    hs-invocations");
   1540       puts("    ds-invocations");
   1541       puts("    cs-invocations");
   1542    }
   1543 
   1544 #ifdef HAVE_GALLIUM_EXTRA_HUD
   1545    hud_get_num_disks(1);
   1546    hud_get_num_nics(1);
   1547    hud_get_num_cpufreq(1);
   1548 #endif
   1549 #ifdef HAVE_LIBSENSORS
   1550    hud_get_num_sensors(1);
   1551 #endif
   1552 
   1553    if (screen->get_driver_query_info){
   1554       boolean skipping = false;
   1555       struct pipe_driver_query_info info;
   1556       num_queries = screen->get_driver_query_info(screen, 0, NULL);
   1557 
   1558       for (i = 0; i < num_queries; i++){
   1559          screen->get_driver_query_info(screen, i, &info);
   1560          if (info.flags & PIPE_DRIVER_QUERY_FLAG_DONT_LIST) {
   1561             if (!skipping)
   1562                puts("    ...");
   1563             skipping = true;
   1564          } else {
   1565             printf("    %s\n", info.name);
   1566             skipping = false;
   1567          }
   1568       }
   1569    }
   1570 
   1571    puts("");
   1572    fflush(stdout);
   1573 }
   1574 
   1575 static void
   1576 hud_unset_draw_context(struct hud_context *hud)
   1577 {
   1578    struct pipe_context *pipe = hud->pipe;
   1579 
   1580    if (!pipe)
   1581       return;
   1582 
   1583    pipe_sampler_view_reference(&hud->font_sampler_view, NULL);
   1584 
   1585    if (hud->fs_color) {
   1586       pipe->delete_fs_state(pipe, hud->fs_color);
   1587       hud->fs_color = NULL;
   1588    }
   1589    if (hud->fs_text) {
   1590       pipe->delete_fs_state(pipe, hud->fs_text);
   1591       hud->fs_text = NULL;
   1592    }
   1593    if (hud->vs) {
   1594       pipe->delete_vs_state(pipe, hud->vs);
   1595       hud->vs = NULL;
   1596    }
   1597 
   1598    hud->cso = NULL;
   1599    hud->pipe = NULL;
   1600 }
   1601 
   1602 static bool
   1603 hud_set_draw_context(struct hud_context *hud, struct cso_context *cso)
   1604 {
   1605    struct pipe_context *pipe = cso_get_pipe_context(cso);
   1606 
   1607    assert(!hud->pipe);
   1608    hud->pipe = pipe;
   1609    hud->cso = cso;
   1610 
   1611    struct pipe_sampler_view view_templ;
   1612    u_sampler_view_default_template(
   1613          &view_templ, hud->font.texture, hud->font.texture->format);
   1614    hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture,
   1615                                                       &view_templ);
   1616    if (!hud->font_sampler_view)
   1617       goto fail;
   1618 
   1619    /* fragment shader */
   1620    hud->fs_color =
   1621          util_make_fragment_passthrough_shader(pipe,
   1622                                                TGSI_SEMANTIC_COLOR,
   1623                                                TGSI_INTERPOLATE_CONSTANT,
   1624                                                TRUE);
   1625 
   1626    {
   1627       /* Read a texture and do .xxxx swizzling. */
   1628       static const char *fragment_shader_text = {
   1629          "FRAG\n"
   1630          "DCL IN[0], GENERIC[0], LINEAR\n"
   1631          "DCL SAMP[0]\n"
   1632          "DCL SVIEW[0], RECT, FLOAT\n"
   1633          "DCL OUT[0], COLOR[0]\n"
   1634          "DCL TEMP[0]\n"
   1635 
   1636          "TEX TEMP[0], IN[0], SAMP[0], RECT\n"
   1637          "MOV OUT[0], TEMP[0].xxxx\n"
   1638          "END\n"
   1639       };
   1640 
   1641       struct tgsi_token tokens[1000];
   1642       struct pipe_shader_state state;
   1643 
   1644       if (!tgsi_text_translate(fragment_shader_text, tokens, ARRAY_SIZE(tokens))) {
   1645          assert(0);
   1646          goto fail;
   1647       }
   1648       pipe_shader_state_from_tgsi(&state, tokens);
   1649       hud->fs_text = pipe->create_fs_state(pipe, &state);
   1650    }
   1651 
   1652    /* vertex shader */
   1653    {
   1654       static const char *vertex_shader_text = {
   1655          "VERT\n"
   1656          "DCL IN[0..1]\n"
   1657          "DCL OUT[0], POSITION\n"
   1658          "DCL OUT[1], COLOR[0]\n" /* color */
   1659          "DCL OUT[2], GENERIC[0]\n" /* texcoord */
   1660          /* [0] = color,
   1661           * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset)
   1662           * [2] = (xscale, yscale, 0, 0) */
   1663          "DCL CONST[0][0..2]\n"
   1664          "DCL TEMP[0]\n"
   1665          "IMM[0] FLT32 { -1, 0, 0, 1 }\n"
   1666 
   1667          /* v = in * (xscale, yscale) + (xoffset, yoffset) */
   1668          "MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n"
   1669          /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */
   1670          "MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n"
   1671          "MOV OUT[0].zw, IMM[0]\n"
   1672 
   1673          "MOV OUT[1], CONST[0][0]\n"
   1674          "MOV OUT[2], IN[1]\n"
   1675          "END\n"
   1676       };
   1677 
   1678       struct tgsi_token tokens[1000];
   1679       struct pipe_shader_state state;
   1680       if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) {
   1681          assert(0);
   1682          goto fail;
   1683       }
   1684       pipe_shader_state_from_tgsi(&state, tokens);
   1685       hud->vs = pipe->create_vs_state(pipe, &state);
   1686    }
   1687 
   1688    return true;
   1689 
   1690 fail:
   1691    hud_unset_draw_context(hud);
   1692    fprintf(stderr, "hud: failed to set a draw context");
   1693    return false;
   1694 }
   1695 
   1696 static void
   1697 hud_unset_record_context(struct hud_context *hud)
   1698 {
   1699    struct pipe_context *pipe = hud->record_pipe;
   1700    struct hud_pane *pane, *pane_tmp;
   1701    struct hud_graph *graph, *graph_tmp;
   1702 
   1703    if (!pipe)
   1704       return;
   1705 
   1706    LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) {
   1707       LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) {
   1708          LIST_DEL(&graph->head);
   1709          hud_graph_destroy(graph, pipe);
   1710       }
   1711       LIST_DEL(&pane->head);
   1712       FREE(pane);
   1713    }
   1714 
   1715    hud_batch_query_cleanup(&hud->batch_query, pipe);
   1716    hud->record_pipe = NULL;
   1717 }
   1718 
   1719 static void
   1720 hud_set_record_context(struct hud_context *hud, struct pipe_context *pipe)
   1721 {
   1722    hud->record_pipe = pipe;
   1723 }
   1724 
   1725 /**
   1726  * Create the HUD.
   1727  *
   1728  * If "share" is non-NULL and GALLIUM_HUD_SHARE=x,y is set, increment the
   1729  * reference counter of "share", set "cso" as the recording or drawing context
   1730  * according to the environment variable, and return "share".
   1731  * This allows sharing the HUD instance within a multi-context share group,
   1732  * record queries in one context and draw them in another.
   1733  */
   1734 struct hud_context *
   1735 hud_create(struct cso_context *cso, struct hud_context *share)
   1736 {
   1737    const char *share_env = debug_get_option("GALLIUM_HUD_SHARE", NULL);
   1738    unsigned record_ctx = 0, draw_ctx = 0;
   1739 
   1740    if (share_env && sscanf(share_env, "%u,%u", &record_ctx, &draw_ctx) != 2)
   1741       share_env = NULL;
   1742 
   1743    if (share && share_env) {
   1744       /* All contexts in a share group share the HUD instance.
   1745        * Only one context can record queries and only one context
   1746        * can draw the HUD.
   1747        *
   1748        * GALLIUM_HUD_SHARE=x,y determines the context indices.
   1749        */
   1750       int context_id = p_atomic_inc_return(&share->refcount) - 1;
   1751 
   1752       if (context_id == record_ctx) {
   1753          assert(!share->record_pipe);
   1754          hud_set_record_context(share, cso_get_pipe_context(cso));
   1755       }
   1756 
   1757       if (context_id == draw_ctx) {
   1758          assert(!share->pipe);
   1759          hud_set_draw_context(share, cso);
   1760       }
   1761 
   1762       return share;
   1763    }
   1764 
   1765    struct pipe_screen *screen = cso_get_pipe_context(cso)->screen;
   1766    struct hud_context *hud;
   1767    unsigned i;
   1768    const char *env = debug_get_option("GALLIUM_HUD", NULL);
   1769 #ifdef PIPE_OS_UNIX
   1770    unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0);
   1771    static boolean sig_handled = FALSE;
   1772    struct sigaction action = {};
   1773 #endif
   1774    huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE);
   1775 
   1776    if (!env || !*env)
   1777       return NULL;
   1778 
   1779    if (strcmp(env, "help") == 0) {
   1780       print_help(screen);
   1781       return NULL;
   1782    }
   1783 
   1784    hud = CALLOC_STRUCT(hud_context);
   1785    if (!hud)
   1786       return NULL;
   1787 
   1788    /* font (the context is only used for the texture upload) */
   1789    if (!util_font_create(cso_get_pipe_context(cso),
   1790                          UTIL_FONT_FIXED_8X13, &hud->font)) {
   1791       FREE(hud);
   1792       return NULL;
   1793    }
   1794 
   1795    hud->refcount = 1;
   1796    hud->has_srgb = screen->is_format_supported(screen,
   1797                                                PIPE_FORMAT_B8G8R8A8_SRGB,
   1798                                                PIPE_TEXTURE_2D, 0,
   1799                                                PIPE_BIND_RENDER_TARGET) != 0;
   1800 
   1801    /* blend state */
   1802    hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA;
   1803 
   1804    hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA;
   1805    hud->alpha_blend.rt[0].blend_enable = 1;
   1806    hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD;
   1807    hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
   1808    hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
   1809    hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD;
   1810    hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
   1811    hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
   1812 
   1813    /* rasterizer */
   1814    hud->rasterizer.half_pixel_center = 1;
   1815    hud->rasterizer.bottom_edge_rule = 1;
   1816    hud->rasterizer.depth_clip = 1;
   1817    hud->rasterizer.line_width = 1;
   1818    hud->rasterizer.line_last_pixel = 1;
   1819 
   1820    hud->rasterizer_aa_lines = hud->rasterizer;
   1821    hud->rasterizer_aa_lines.line_smooth = 1;
   1822 
   1823    /* vertex elements */
   1824    for (i = 0; i < 2; i++) {
   1825       hud->velems[i].src_offset = i * 2 * sizeof(float);
   1826       hud->velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT;
   1827       hud->velems[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
   1828    }
   1829 
   1830    /* sampler state (for font drawing) */
   1831    hud->font_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
   1832    hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
   1833    hud->font_sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
   1834    hud->font_sampler_state.normalized_coords = 0;
   1835 
   1836    /* constants */
   1837    hud->constbuf.buffer_size = sizeof(hud->constants);
   1838    hud->constbuf.user_buffer = &hud->constants;
   1839 
   1840    LIST_INITHEAD(&hud->pane_list);
   1841 
   1842    /* setup sig handler once for all hud contexts */
   1843 #ifdef PIPE_OS_UNIX
   1844    if (!sig_handled && signo != 0) {
   1845       action.sa_sigaction = &signal_visible_handler;
   1846       action.sa_flags = SA_SIGINFO;
   1847 
   1848       if (signo >= NSIG)
   1849          fprintf(stderr, "gallium_hud: invalid signal %u\n", signo);
   1850       else if (sigaction(signo, &action, NULL) < 0)
   1851          fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo);
   1852       fflush(stderr);
   1853 
   1854       sig_handled = TRUE;
   1855    }
   1856 #endif
   1857 
   1858    if (record_ctx == 0)
   1859       hud_set_record_context(hud, cso_get_pipe_context(cso));
   1860    if (draw_ctx == 0)
   1861       hud_set_draw_context(hud, cso);
   1862 
   1863    hud_parse_env_var(hud, screen, env);
   1864    return hud;
   1865 }
   1866 
   1867 /**
   1868  * Destroy a HUD. If the HUD has several users, decrease the reference counter
   1869  * and detach the context from the HUD.
   1870  */
   1871 void
   1872 hud_destroy(struct hud_context *hud, struct cso_context *cso)
   1873 {
   1874    if (!cso || hud->record_pipe == cso_get_pipe_context(cso))
   1875       hud_unset_record_context(hud);
   1876 
   1877    if (!cso || hud->cso == cso)
   1878       hud_unset_draw_context(hud);
   1879 
   1880    if (p_atomic_dec_zero(&hud->refcount)) {
   1881       pipe_resource_reference(&hud->font.texture, NULL);
   1882       FREE(hud);
   1883    }
   1884 }
   1885 
   1886 void
   1887 hud_add_queue_for_monitoring(struct hud_context *hud,
   1888                              struct util_queue_monitoring *queue_info)
   1889 {
   1890    assert(!hud->monitored_queue);
   1891    hud->monitored_queue = queue_info;
   1892 }
   1893