gallium: change comments to remove 'state tracker'
[mesa.git] / src / gallium / auxiliary / hud / hud_context.c
index e3fcad22f792179fddab9af7ef92160af9b0e546..0cd3307a1a5f7cd01d25ddd9e98fdc85bf508198 100644 (file)
@@ -27,7 +27,7 @@
 
 /* This head-up display module can draw transparent graphs on top of what
  * the app is rendering, visualizing various data like framerate, cpu load,
- * performance counters, etc. It can be hook up into any state tracker.
+ * performance counters, etc. It can be hook up into any gallium frontend.
  *
  * The HUD is controlled with the GALLIUM_HUD environment variable.
  * Set GALLIUM_HUD=help for more info.
@@ -42,7 +42,7 @@
 
 #include "cso_cache/cso_context.h"
 #include "util/u_draw_quad.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 #include "util/u_math.h"
@@ -55,6 +55,7 @@
 
 /* Control the visibility of all HUD contexts */
 static boolean huds_visible = TRUE;
+static int hud_scale = 1;
 
 
 #ifdef PIPE_OS_UNIX
@@ -74,21 +75,23 @@ hud_draw_colored_prims(struct hud_context *hud, unsigned prim,
    struct cso_context *cso = hud->cso;
    unsigned size = num_vertices * hud->color_prims.vbuf.stride;
 
-   assert(size <= hud->color_prims.buffer_size);
+   /* If a recording context is inactive, don't draw anything. */
+   if (size > hud->color_prims.buffer_size)
+      return;
+
    memcpy(hud->color_prims.vertices, buffer, size);
 
    hud->constants.color[0] = r;
    hud->constants.color[1] = g;
    hud->constants.color[2] = b;
    hud->constants.color[3] = a;
-   hud->constants.translate[0] = (float) xoffset;
-   hud->constants.translate[1] = (float) yoffset;
-   hud->constants.scale[0] = 1;
-   hud->constants.scale[1] = yscale;
+   hud->constants.translate[0] = (float) (xoffset * hud_scale);
+   hud->constants.translate[1] = (float) (yoffset * hud_scale);
+   hud->constants.scale[0] = hud_scale;
+   hud->constants.scale[1] = yscale * hud_scale;
    cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
 
-   cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso),
-                          1, &hud->color_prims.vbuf);
+   cso_set_vertex_buffers(cso, 0, 1, &hud->color_prims.vbuf);
    cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
    cso_draw_arrays(cso, prim, 0, num_vertices);
 
@@ -147,7 +150,7 @@ hud_draw_string(struct hud_context *hud, unsigned x, unsigned y,
 
    va_list ap;
    va_start(ap, str);
-   util_vsnprintf(buf, sizeof(buf), str, ap);
+   vsnprintf(buf, sizeof(buf), str, ap);
    va_end(ap);
 
    if (!*s)
@@ -221,6 +224,7 @@ number_to_human_readable(double num, enum pipe_driver_query_type type,
    static const char *volt_units[] = {" mV", " V"};
    static const char *amp_units[] = {" mA", " A"};
    static const char *watt_units[] = {" mW", " W"};
+   static const char *float_units[] = {""};
 
    const char **units;
    unsigned max_unit;
@@ -249,6 +253,10 @@ number_to_human_readable(double num, enum pipe_driver_query_type type,
       max_unit = ARRAY_SIZE(temperature_units)-1;
       units = temperature_units;
       break;
+   case PIPE_DRIVER_QUERY_TYPE_FLOAT:
+      max_unit = ARRAY_SIZE(float_units)-1;
+      units = float_units;
+      break;
    case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE:
       max_unit = ARRAY_SIZE(percent_units)-1;
       units = percent_units;
@@ -390,6 +398,26 @@ hud_pane_accumulate_vertices(struct hud_context *hud,
    hud->whitelines.num_vertices += num/2;
 }
 
+static void
+hud_pane_accumulate_vertices_simple(struct hud_context *hud,
+                                    const struct hud_pane *pane)
+{
+   struct hud_graph *gr;
+   unsigned i;
+   char str[32];
+
+   /* draw info below the pane */
+   i = 0;
+   LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
+      unsigned x = pane->x1;
+      unsigned y = pane->y_simple + i*hud->font.glyph_height;
+
+      number_to_human_readable(gr->current_value, pane->type, str);
+      hud_draw_string(hud, x, y, "%s: %s", gr->name, str);
+      i++;
+   }
+}
+
 static void
 hud_pane_draw_colored_objects(struct hud_context *hud,
                               const struct hud_pane *pane)
@@ -511,7 +539,7 @@ hud_draw_results(struct hud_context *hud, struct pipe_resource *tex)
    cso_set_tesseval_shader_handle(cso, NULL);
    cso_set_geometry_shader_handle(cso, NULL);
    cso_set_vertex_shader_handle(cso, hud->vs);
-   cso_set_vertex_elements(cso, 2, hud->velems);
+   cso_set_vertex_elements(cso, &hud->velems);
    cso_set_render_condition(cso, NULL, FALSE, 0);
    cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1,
                          &hud->font_sampler_view);
@@ -529,16 +557,32 @@ hud_draw_results(struct hud_context *hud, struct pipe_resource *tex)
       hud->constants.color[3] = 0.666f;
       hud->constants.translate[0] = 0;
       hud->constants.translate[1] = 0;
-      hud->constants.scale[0] = 1;
-      hud->constants.scale[1] = 1;
+      hud->constants.scale[0] = hud_scale;
+      hud->constants.scale[1] = hud_scale;
 
       cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
-      cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
-                             &hud->bg.vbuf);
+
+      cso_set_vertex_buffers(cso, 0, 1, &hud->bg.vbuf);
       cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices);
    }
    pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL);
 
+   /* draw accumulated vertices for text */
+   if (hud->text.num_vertices) {
+      cso_set_vertex_buffers(cso, 0, 1, &hud->text.vbuf);
+      cso_set_fragment_shader_handle(hud->cso, hud->fs_text);
+      cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices);
+   }
+   pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL);
+
+   if (hud->simple) {
+      cso_restore_state(cso);
+      cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
+
+      pipe_surface_reference(&surf, NULL);
+      return;
+   }
+
    /* draw accumulated vertices for white lines */
    cso_set_blend(cso, &hud->no_blend);
 
@@ -548,29 +592,19 @@ hud_draw_results(struct hud_context *hud, struct pipe_resource *tex)
    hud->constants.color[3] = 1;
    hud->constants.translate[0] = 0;
    hud->constants.translate[1] = 0;
-   hud->constants.scale[0] = 1;
-   hud->constants.scale[1] = 1;
+   hud->constants.scale[0] = hud_scale;
+   hud->constants.scale[1] = hud_scale;
    cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
 
    if (hud->whitelines.num_vertices) {
-      cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
-                             &hud->whitelines.vbuf);
+      cso_set_vertex_buffers(cso, 0, 1, &hud->whitelines.vbuf);
       cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
       cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices);
    }
    pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL);
 
-   /* draw accumulated vertices for text */
-   cso_set_blend(cso, &hud->alpha_blend);
-   if (hud->text.num_vertices) {
-      cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
-                             &hud->text.vbuf);
-      cso_set_fragment_shader_handle(hud->cso, hud->fs_text);
-      cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices);
-   }
-   pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL);
-
    /* draw the rest */
+   cso_set_blend(cso, &hud->alpha_blend);
    cso_set_rasterizer(cso, &hud->rasterizer_aa_lines);
    LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
       if (pane)
@@ -664,24 +698,61 @@ hud_stop_queries(struct hud_context *hud, struct pipe_context *pipe)
              */
             if (gr->current_value <
                 LIST_ENTRY(struct hud_graph, next, head)->current_value) {
-               LIST_DEL(&gr->head);
-               LIST_ADD(&gr->head, &next->head);
+               list_del(&gr->head);
+               list_add(&gr->head, &next->head);
             }
          }
       }
 
-      hud_pane_accumulate_vertices(hud, pane);
+      if (hud->simple)
+         hud_pane_accumulate_vertices_simple(hud, pane);
+      else
+         hud_pane_accumulate_vertices(hud, pane);
    }
 
    /* unmap the uploader's vertex buffer before drawing */
    u_upload_unmap(pipe->stream_uploader);
 }
 
+/**
+ * Record queries and draw the HUD. The "cso" parameter acts as a filter.
+ * If "cso" is not the recording context, recording is skipped.
+ * If "cso" is not the drawing context, drawing is skipped.
+ * cso == NULL ignores the filter.
+ */
+void
+hud_run(struct hud_context *hud, struct cso_context *cso,
+        struct pipe_resource *tex)
+{
+   struct pipe_context *pipe = cso ? cso_get_pipe_context(cso) : NULL;
+
+   /* If "cso" is the recording or drawing context or NULL, execute
+    * the operation. Otherwise, don't do anything.
+    */
+   if (hud->record_pipe && (!pipe || pipe == hud->record_pipe))
+      hud_stop_queries(hud, hud->record_pipe);
+
+   if (hud->cso && (!cso || cso == hud->cso))
+      hud_draw_results(hud, tex);
+
+   if (hud->record_pipe && (!pipe || pipe == hud->record_pipe))
+      hud_start_queries(hud, hud->record_pipe);
+}
+
+/**
+ * Record query results and assemble vertices if "pipe" is a recording but
+ * not drawing context.
+ */
 void
-hud_run(struct hud_context *hud, struct pipe_resource *tex)
+hud_record_only(struct hud_context *hud, struct pipe_context *pipe)
 {
+   assert(pipe);
+
+   /* If it's a drawing context, only hud_run() records query results. */
+   if (pipe == hud->pipe || pipe != hud->record_pipe)
+      return;
+
    hud_stop_queries(hud, hud->record_pipe);
-   hud_draw_results(hud, tex);
    hud_start_queries(hud, hud->record_pipe);
 }
 
@@ -800,6 +871,7 @@ hud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane)
 static struct hud_pane *
 hud_pane_create(struct hud_context *hud,
                 unsigned x1, unsigned y1, unsigned x2, unsigned y2,
+                unsigned y_simple,
                 unsigned period, uint64_t max_value, uint64_t ceiling,
                 boolean dyn_ceiling, boolean sort_items)
 {
@@ -813,6 +885,7 @@ hud_pane_create(struct hud_context *hud,
    pane->y1 = y1;
    pane->x2 = x2;
    pane->y2 = y2;
+   pane->y_simple = y_simple;
    pane->inner_x1 = x1 + 1;
    pane->inner_x2 = x2 - 1;
    pane->inner_y1 = y1 + 1;
@@ -827,7 +900,7 @@ hud_pane_create(struct hud_context *hud,
    pane->sort_items = sort_items;
    pane->initial_max_value = max_value;
    hud_pane_set_max_value(pane, max_value);
-   LIST_INITHEAD(&pane->graph_list);
+   list_inithead(&pane->graph_list);
    return pane;
 }
 
@@ -875,7 +948,7 @@ hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr)
    gr->color[1] = colors[color][1];
    gr->color[2] = colors[color][2];
    gr->pane = pane;
-   LIST_ADDTAIL(&gr->head, &pane->graph_list);
+   list_addtail(&gr->head, &pane->graph_list);
    pane->num_graphs++;
    pane->next_color++;
 }
@@ -1114,7 +1187,7 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
    char name_a[256], s[256];
    char *name;
    struct hud_pane *pane = NULL;
-   unsigned x = 10, y = 10;
+   unsigned x = 10, y = 10, y_simple = 10;
    unsigned width = 251, height = 100;
    unsigned period = 500 * 1000;  /* default period (1/2 second) */
    uint64_t ceiling = UINT64_MAX;
@@ -1124,6 +1197,11 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
    boolean sort_items = false;
    const char *period_env;
 
+   if (strncmp(env, "simple,", 7) == 0) {
+      hud->simple = true;
+      env += 7;
+   }
+
    /*
     * The GALLIUM_HUD_PERIOD env var sets the graph update rate.
     * The env var is in seconds (a float).
@@ -1138,6 +1216,8 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
    }
 
    while ((num = parse_string(env, name_a)) != 0) {
+      bool added = true;
+
       env += num;
 
       /* check for explicit location, size and etc. settings */
@@ -1152,8 +1232,8 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
      column_width = width > column_width ? width : column_width;
 
       if (!pane) {
-         pane = hud_pane_create(hud, x, y, x + width, y + height, period, 10,
-                                ceiling, dyn_ceiling, sort_items);
+         pane = hud_pane_create(hud, x, y, x + width, y + height, y_simple,
+                                period, 10, ceiling, dyn_ceiling, sort_items);
          if (!pane)
             return;
       }
@@ -1164,13 +1244,16 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
       }
 
       /* Add a graph. */
-#if HAVE_GALLIUM_EXTRA_HUD || HAVE_LIBSENSORS
+#if defined(HAVE_GALLIUM_EXTRA_HUD) || defined(HAVE_LIBSENSORS)
       char arg_name[64];
 #endif
       /* IF YOU CHANGE THIS, UPDATE print_help! */
       if (strcmp(name, "fps") == 0) {
          hud_fps_graph_install(pane);
       }
+      else if (strcmp(name, "frametime") == 0) {
+         hud_frametime_graph_install(pane);
+      }
       else if (strcmp(name, "cpu") == 0) {
          hud_cpu_graph_install(pane, ALL_CPUS);
       }
@@ -1192,7 +1275,7 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
       else if (strcmp(name, "main-thread-busy") == 0) {
          hud_thread_busy_install(pane, name, true);
       }
-#if HAVE_GALLIUM_EXTRA_HUD
+#ifdef HAVE_GALLIUM_EXTRA_HUD
       else if (sscanf(name, "nic-rx-%s", arg_name) == 1) {
          hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX);
       }
@@ -1224,7 +1307,7 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
          pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
       }
 #endif
-#if HAVE_LIBSENSORS
+#ifdef HAVE_LIBSENSORS
       else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) {
          hud_sensors_temp_graph_install(pane, arg_name,
                                         SENSORS_TEMP_CURRENT);
@@ -1307,6 +1390,7 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
                                           screen, name)) {
                fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name);
                fflush(stderr);
+               added = false;
             }
          }
       }
@@ -1349,7 +1433,7 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
          env += num;
 
          strip_hyphens(s);
-         if (!LIST_IS_EMPTY(&pane->graph_list)) {
+         if (added && !list_is_empty(&pane->graph_list)) {
             struct hud_graph *graph;
             graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head);
             strncpy(graph->name, s, sizeof(graph->name)-1);
@@ -1372,10 +1456,11 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
             break;
 
          y += height + hud->font.glyph_height * (pane->num_graphs + 2);
+         y_simple += hud->font.glyph_height * (pane->num_graphs + 1);
          height = 100;
 
          if (pane && pane->num_graphs) {
-            LIST_ADDTAIL(&pane->head, &hud->pane_list);
+            list_addtail(&pane->head, &hud->pane_list);
             pane = NULL;
          }
          break;
@@ -1383,11 +1468,12 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
       case ';':
          env++;
          y = 10;
+         y_simple = 10;
          x += column_width + hud->font.glyph_width * 9;
          height = 100;
 
          if (pane && pane->num_graphs) {
-            LIST_ADDTAIL(&pane->head, &hud->pane_list);
+            list_addtail(&pane->head, &hud->pane_list);
             pane = NULL;
          }
 
@@ -1410,7 +1496,7 @@ hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
 
    if (pane) {
       if (pane->num_graphs) {
-         LIST_ADDTAIL(&pane->head, &hud->pane_list);
+         list_addtail(&pane->head, &hud->pane_list);
       }
       else {
          FREE(pane);
@@ -1471,10 +1557,15 @@ print_help(struct pipe_screen *screen)
    puts("  the Y axis does not go above the restriction imposed by 'c' while");
    puts("  still adjusting the value of the Y axis down when appropriate.");
    puts("");
+   puts("  You can change behavior of the whole HUD by adding these options at");
+   puts("  the beginning of the environment variable:");
+   puts("  'simple,' disables all the fancy stuff and only draws text.");
+   puts("");
    puts("  Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\"");
    puts("");
    puts("  Available names:");
    puts("    fps");
+   puts("    frametime");
    puts("    cpu");
 
    for (i = 0; i < num_cpus; i++)
@@ -1499,12 +1590,12 @@ print_help(struct pipe_screen *screen)
       puts("    cs-invocations");
    }
 
-#if HAVE_GALLIUM_EXTRA_HUD
+#ifdef HAVE_GALLIUM_EXTRA_HUD
    hud_get_num_disks(1);
    hud_get_num_nics(1);
    hud_get_num_cpufreq(1);
 #endif
-#if HAVE_LIBSENSORS
+#ifdef HAVE_LIBSENSORS
    hud_get_num_sensors(1);
 #endif
 
@@ -1663,10 +1754,10 @@ hud_unset_record_context(struct hud_context *hud)
 
    LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) {
       LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) {
-         LIST_DEL(&graph->head);
+         list_del(&graph->head);
          hud_graph_destroy(graph, pipe);
       }
-      LIST_DEL(&pane->head);
+      list_del(&pane->head);
       FREE(pane);
    }
 
@@ -1680,9 +1771,46 @@ hud_set_record_context(struct hud_context *hud, struct pipe_context *pipe)
    hud->record_pipe = pipe;
 }
 
+/**
+ * Create the HUD.
+ *
+ * If "share" is non-NULL and GALLIUM_HUD_SHARE=x,y is set, increment the
+ * reference counter of "share", set "cso" as the recording or drawing context
+ * according to the environment variable, and return "share".
+ * This allows sharing the HUD instance within a multi-context share group,
+ * record queries in one context and draw them in another.
+ */
 struct hud_context *
-hud_create(struct cso_context *cso)
+hud_create(struct cso_context *cso, struct hud_context *share)
 {
+   const char *share_env = debug_get_option("GALLIUM_HUD_SHARE", NULL);
+   unsigned record_ctx = 0, draw_ctx = 0;
+
+   if (share_env && sscanf(share_env, "%u,%u", &record_ctx, &draw_ctx) != 2)
+      share_env = NULL;
+
+   if (share && share_env) {
+      /* All contexts in a share group share the HUD instance.
+       * Only one context can record queries and only one context
+       * can draw the HUD.
+       *
+       * GALLIUM_HUD_SHARE=x,y determines the context indices.
+       */
+      int context_id = p_atomic_inc_return(&share->refcount) - 1;
+
+      if (context_id == record_ctx) {
+         assert(!share->record_pipe);
+         hud_set_record_context(share, cso_get_pipe_context(cso));
+      }
+
+      if (context_id == draw_ctx) {
+         assert(!share->pipe);
+         hud_set_draw_context(share, cso);
+      }
+
+      return share;
+   }
+
    struct pipe_screen *screen = cso_get_pipe_context(cso)->screen;
    struct hud_context *hud;
    unsigned i;
@@ -1690,9 +1818,12 @@ hud_create(struct cso_context *cso)
 #ifdef PIPE_OS_UNIX
    unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0);
    static boolean sig_handled = FALSE;
-   struct sigaction action = {};
+   struct sigaction action;
+
+   memset(&action, 0, sizeof(action));
 #endif
    huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE);
+   hud_scale = debug_get_num_option("GALLIUM_HUD_SCALE", 1);
 
    if (!env || !*env)
       return NULL;
@@ -1713,9 +1844,10 @@ hud_create(struct cso_context *cso)
       return NULL;
    }
 
+   hud->refcount = 1;
    hud->has_srgb = screen->is_format_supported(screen,
                                                PIPE_FORMAT_B8G8R8A8_SRGB,
-                                               PIPE_TEXTURE_2D, 0,
+                                               PIPE_TEXTURE_2D, 0, 0,
                                                PIPE_BIND_RENDER_TARGET) != 0;
 
    /* blend state */
@@ -1733,7 +1865,8 @@ hud_create(struct cso_context *cso)
    /* rasterizer */
    hud->rasterizer.half_pixel_center = 1;
    hud->rasterizer.bottom_edge_rule = 1;
-   hud->rasterizer.depth_clip = 1;
+   hud->rasterizer.depth_clip_near = 1;
+   hud->rasterizer.depth_clip_far = 1;
    hud->rasterizer.line_width = 1;
    hud->rasterizer.line_last_pixel = 1;
 
@@ -1741,10 +1874,11 @@ hud_create(struct cso_context *cso)
    hud->rasterizer_aa_lines.line_smooth = 1;
 
    /* vertex elements */
+   hud->velems.count = 2;
    for (i = 0; i < 2; i++) {
-      hud->velems[i].src_offset = i * 2 * sizeof(float);
-      hud->velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT;
-      hud->velems[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
+      hud->velems.velems[i].src_offset = i * 2 * sizeof(float);
+      hud->velems.velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT;
+      hud->velems.velems[i].vertex_buffer_index = 0;
    }
 
    /* sampler state (for font drawing) */
@@ -1757,13 +1891,7 @@ hud_create(struct cso_context *cso)
    hud->constbuf.buffer_size = sizeof(hud->constants);
    hud->constbuf.user_buffer = &hud->constants;
 
-   LIST_INITHEAD(&hud->pane_list);
-
-   if (!hud_set_draw_context(hud, cso)) {
-      pipe_resource_reference(&hud->font.texture, NULL);
-      FREE(hud);
-      return NULL;
-   }
+   list_inithead(&hud->pane_list);
 
    /* setup sig handler once for all hud contexts */
 #ifdef PIPE_OS_UNIX
@@ -1781,18 +1909,32 @@ hud_create(struct cso_context *cso)
    }
 #endif
 
-   hud_set_record_context(hud, cso_get_pipe_context(cso));
+   if (record_ctx == 0)
+      hud_set_record_context(hud, cso_get_pipe_context(cso));
+   if (draw_ctx == 0)
+      hud_set_draw_context(hud, cso);
+
    hud_parse_env_var(hud, screen, env);
    return hud;
 }
 
+/**
+ * Destroy a HUD. If the HUD has several users, decrease the reference counter
+ * and detach the context from the HUD.
+ */
 void
-hud_destroy(struct hud_context *hud)
+hud_destroy(struct hud_context *hud, struct cso_context *cso)
 {
-   hud_unset_record_context(hud);
-   hud_unset_draw_context(hud);
-   pipe_resource_reference(&hud->font.texture, NULL);
-   FREE(hud);
+   if (!cso || hud->record_pipe == cso_get_pipe_context(cso))
+      hud_unset_record_context(hud);
+
+   if (!cso || hud->cso == cso)
+      hud_unset_draw_context(hud);
+
+   if (p_atomic_dec_zero(&hud->refcount)) {
+      pipe_resource_reference(&hud->font.texture, NULL);
+      FREE(hud);
+   }
 }
 
 void