From bd57f45168188caabce3aebed287a9d32bc00537 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 19 Nov 2017 21:29:46 +0100 Subject: [PATCH] gallium/hud: add HUD sharing within a context share group MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This is needed for profiling multi-context applications like Chrome. One context can record queries and another context can draw the HUD. Reviewed-by: Nicolai Hähnle --- src/gallium/auxiliary/hud/hud_context.c | 103 ++++++++++++++++--- src/gallium/auxiliary/hud/hud_context.h | 3 + src/gallium/auxiliary/hud/hud_private.h | 2 + src/gallium/state_trackers/dri/dri_context.c | 12 ++- 4 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/gallium/auxiliary/hud/hud_context.c b/src/gallium/auxiliary/hud/hud_context.c index 783dafd75f6..bd7c8cbb381 100644 --- a/src/gallium/auxiliary/hud/hud_context.c +++ b/src/gallium/auxiliary/hud/hud_context.c @@ -680,12 +680,45 @@ hud_stop_queries(struct hud_context *hud, struct pipe_context *pipe) 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_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); } @@ -1684,9 +1717,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, 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; @@ -1717,6 +1787,7 @@ hud_create(struct cso_context *cso, struct hud_context *share) return NULL; } + hud->refcount = 1; hud->has_srgb = screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB, PIPE_TEXTURE_2D, 0, @@ -1763,12 +1834,6 @@ hud_create(struct cso_context *cso, struct hud_context *share) LIST_INITHEAD(&hud->pane_list); - if (!hud_set_draw_context(hud, cso)) { - pipe_resource_reference(&hud->font.texture, NULL); - FREE(hud); - return NULL; - } - /* setup sig handler once for all hud contexts */ #ifdef PIPE_OS_UNIX if (!sig_handled && signo != 0) { @@ -1785,18 +1850,32 @@ hud_create(struct cso_context *cso, struct hud_context *share) } #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, 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 diff --git a/src/gallium/auxiliary/hud/hud_context.h b/src/gallium/auxiliary/hud/hud_context.h index 128d4ef9ab8..99e6f8d7e67 100644 --- a/src/gallium/auxiliary/hud/hud_context.h +++ b/src/gallium/auxiliary/hud/hud_context.h @@ -44,6 +44,9 @@ void hud_run(struct hud_context *hud, struct cso_context *cso, struct pipe_resource *tex); +void +hud_record_only(struct hud_context *hud, struct pipe_context *pipe); + void hud_add_queue_for_monitoring(struct hud_context *hud, struct util_queue_monitoring *queue_info); diff --git a/src/gallium/auxiliary/hud/hud_private.h b/src/gallium/auxiliary/hud/hud_private.h index c55d64f5eb6..7f0294badd3 100644 --- a/src/gallium/auxiliary/hud/hud_private.h +++ b/src/gallium/auxiliary/hud/hud_private.h @@ -40,6 +40,8 @@ enum hud_counter { }; struct hud_context { + int refcount; + /* Context where queries are executed. */ struct pipe_context *record_pipe; diff --git a/src/gallium/state_trackers/dri/dri_context.c b/src/gallium/state_trackers/dri/dri_context.c index d4ac8adee1b..6e28553146f 100644 --- a/src/gallium/state_trackers/dri/dri_context.c +++ b/src/gallium/state_trackers/dri/dri_context.c @@ -116,8 +116,10 @@ dri_create_context(gl_api api, const struct gl_config * visual, && (ctx_config->release_behavior == __DRI_CTX_RELEASE_BEHAVIOR_NONE)) attribs.flags |= ST_CONTEXT_FLAG_RELEASE_NONE; + struct dri_context *share_ctx = NULL; if (sharedContextPrivate) { - st_share = ((struct dri_context *)sharedContextPrivate)->st; + share_ctx = (struct dri_context *)sharedContextPrivate; + st_share = share_ctx->st; } ctx = CALLOC_STRUCT(dri_context); @@ -168,7 +170,8 @@ dri_create_context(gl_api api, const struct gl_config * visual, if (ctx->st->cso_context) { ctx->pp = pp_init(ctx->st->pipe, screen->pp_enabled, ctx->st->cso_context); - ctx->hud = hud_create(ctx->st->cso_context, NULL); + ctx->hud = hud_create(ctx->st->cso_context, + share_ctx ? share_ctx->hud : NULL); } /* Do this last. */ @@ -222,6 +225,7 @@ dri_destroy_context(__DRIcontext * cPriv) free(ctx); } +/* This is called inside MakeCurrent to unbind the context. */ GLboolean dri_unbind_context(__DRIcontext * cPriv) { @@ -236,6 +240,10 @@ dri_unbind_context(__DRIcontext * cPriv) if (st->thread_finish) st->thread_finish(st); + /* Record HUD queries for the duration the context was "current". */ + if (ctx->hud) + hud_record_only(ctx->hud, st->pipe); + stapi->make_current(stapi, NULL, NULL, NULL); } } -- 2.30.2