+ return true;
+
+fail:
+ hud_unset_draw_context(hud);
+ fprintf(stderr, "hud: failed to set a draw context");
+ return false;
+}
+
+static void
+hud_unset_record_context(struct hud_context *hud)
+{
+ struct pipe_context *pipe = hud->record_pipe;
+ struct hud_pane *pane, *pane_tmp;
+ struct hud_graph *graph, *graph_tmp;
+
+ if (!pipe)
+ return;
+
+ 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);
+ hud_graph_destroy(graph, pipe);
+ }
+ list_del(&pane->head);
+ FREE(pane);
+ }
+
+ hud_batch_query_cleanup(&hud->batch_query, pipe);
+ hud->record_pipe = NULL;
+}
+
+static void
+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, 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;
+ const char *env = debug_get_option("GALLIUM_HUD", NULL);
+#ifdef PIPE_OS_UNIX
+ unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0);
+ static boolean sig_handled = FALSE;
+ struct sigaction action;
+
+ 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;
+
+ if (strcmp(env, "help") == 0) {
+ print_help(screen);
+ return NULL;
+ }
+
+ hud = CALLOC_STRUCT(hud_context);
+ if (!hud)
+ return NULL;
+
+ /* font (the context is only used for the texture upload) */
+ if (!util_font_create(cso_get_pipe_context(cso),
+ UTIL_FONT_FIXED_8X13, &hud->font)) {
+ FREE(hud);
+ return NULL;
+ }
+
+ hud->refcount = 1;
+ hud->has_srgb = screen->is_format_supported(screen,
+ PIPE_FORMAT_B8G8R8A8_SRGB,
+ PIPE_TEXTURE_2D, 0, 0,
+ PIPE_BIND_RENDER_TARGET) != 0;
+
+ /* blend state */
+ hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA;
+
+ hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA;
+ hud->alpha_blend.rt[0].blend_enable = 1;
+ hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD;
+ hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+ hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD;
+ hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
+ hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
+
+ /* rasterizer */
+ hud->rasterizer.half_pixel_center = 1;
+ hud->rasterizer.bottom_edge_rule = 1;
+ hud->rasterizer.depth_clip_near = 1;
+ hud->rasterizer.depth_clip_far = 1;
+ hud->rasterizer.line_width = 1;
+ hud->rasterizer.line_last_pixel = 1;
+
+ hud->rasterizer_aa_lines = hud->rasterizer;
+ hud->rasterizer_aa_lines.line_smooth = 1;
+