[Mesa-dev] [PATCH 12/12] gallium/hud: add HUD sharing within a context share group

Nicolai Hähnle nhaehnle at gmail.com
Wed Nov 22 19:01:15 UTC 2017


On 21.11.2017 18:46, Marek Olšák wrote:
> From: Marek Olšák <marek.olsak at amd.com>
> 
> This is needed for profiling multi-context applications like Chrome.
> One context can record queries and another context can draw the HUD.
> ---
>   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 783dafd..2586b5f 100644
> --- a/src/gallium/auxiliary/hud/hud_context.c
> +++ b/src/gallium/auxiliary/hud/hud_context.c
> @@ -673,26 +673,59 @@ hud_stop_queries(struct hud_context *hud, struct pipe_context *pipe)
>            }
>         }
>   
>         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_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);
>   }
>   
>   static void
>   fixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10)
>   {
>      if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0)
>         *exp10 = (*exp10 / 1000) * 1024;
>   }
>   
> @@ -1677,23 +1710,60 @@ hud_unset_record_context(struct hud_context *hud)
>      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, draw_ctx;
> +
> +   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 = {};
>   #endif
>      huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE);
> @@ -1710,20 +1780,21 @@ hud_create(struct cso_context *cso, struct hud_context *share)
>      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,
>                                                  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;
> @@ -1756,53 +1827,61 @@ hud_create(struct cso_context *cso, struct hud_context *share)
>      hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>      hud->font_sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>      hud->font_sampler_state.normalized_coords = 0;
>   
>      /* constants */
>      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;
> -   }
> -
>      /* setup sig handler once for all hud contexts */
>   #ifdef PIPE_OS_UNIX
>      if (!sig_handled && signo != 0) {
>         action.sa_sigaction = &signal_visible_handler;
>         action.sa_flags = SA_SIGINFO;
>   
>         if (signo >= NSIG)
>            fprintf(stderr, "gallium_hud: invalid signal %u\n", signo);
>         else if (sigaction(signo, &action, NULL) < 0)
>            fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo);
>         fflush(stderr);
>   
>         sig_handled = TRUE;
>      }
>   #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);

These look like record_ctx / draw_ctx would be uninitialized if 
GALLIUM_HUD_SHARE isn't set.

Apart from this, the series is:

Reviewed-by: Nicolai Hähnle <nicolai.haehnle at amd.com>



> +
>      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
>   hud_add_queue_for_monitoring(struct hud_context *hud,
>                                struct util_queue_monitoring *queue_info)
>   {
>      assert(!hud->monitored_queue);
>      hud->monitored_queue = queue_info;
>   }
> diff --git a/src/gallium/auxiliary/hud/hud_context.h b/src/gallium/auxiliary/hud/hud_context.h
> index 128d4ef..99e6f8d 100644
> --- a/src/gallium/auxiliary/hud/hud_context.h
> +++ b/src/gallium/auxiliary/hud/hud_context.h
> @@ -38,14 +38,17 @@ struct hud_context *
>   hud_create(struct cso_context *cso, struct hud_context *share);
>   
>   void
>   hud_destroy(struct hud_context *hud, struct cso_context *cso);
>   
>   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);
>   
>   #endif
> diff --git a/src/gallium/auxiliary/hud/hud_private.h b/src/gallium/auxiliary/hud/hud_private.h
> index c55d64f..7f0294b 100644
> --- a/src/gallium/auxiliary/hud/hud_private.h
> +++ b/src/gallium/auxiliary/hud/hud_private.h
> @@ -33,20 +33,22 @@
>   #include "util/list.h"
>   #include "hud/font.h"
>   
>   enum hud_counter {
>      HUD_COUNTER_OFFLOADED,
>      HUD_COUNTER_DIRECT,
>      HUD_COUNTER_SYNCS,
>   };
>   
>   struct hud_context {
> +   int refcount;
> +
>      /* Context where queries are executed. */
>      struct pipe_context *record_pipe;
>   
>      /* Context where the HUD is drawn: */
>      struct pipe_context *pipe;
>      struct cso_context *cso;
>   
>      struct hud_batch_query_context *batch_query;
>      struct list_head pane_list;
>   
> diff --git a/src/gallium/state_trackers/dri/dri_context.c b/src/gallium/state_trackers/dri/dri_context.c
> index d4ac8ad..6e28553 100644
> --- a/src/gallium/state_trackers/dri/dri_context.c
> +++ b/src/gallium/state_trackers/dri/dri_context.c
> @@ -109,22 +109,24 @@ dri_create_context(gl_api api, const struct gl_config * visual,
>         if (ctx_config->reset_strategy != __DRI_CTX_RESET_NO_NOTIFICATION)
>            attribs.flags |= ST_CONTEXT_FLAG_RESET_NOTIFICATION_ENABLED;
>   
>      if (ctx_config->flags & __DRI_CTX_FLAG_NO_ERROR)
>         attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
>   
>      if ((ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR)
>          && (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);
>      if (ctx == NULL) {
>         *error = __DRI_CTX_ERROR_NO_MEMORY;
>         goto fail;
>      }
>   
>      cPriv->driverPrivate = ctx;
>      ctx->cPriv = cPriv;
> @@ -161,21 +163,22 @@ dri_create_context(gl_api api, const struct gl_config * visual,
>   	 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
>   	 break;
>         }
>         goto fail;
>      }
>      ctx->st->st_manager_private = (void *) ctx;
>      ctx->stapi = stapi;
>   
>      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. */
>      if (ctx->st->start_thread &&
>            driQueryOptionb(&screen->dev->option_cache, "mesa_glthread")) {
>   
>         if (backgroundCallable && backgroundCallable->base.version >= 2 &&
>               backgroundCallable->isThreadSafe) {
>   
>            if (backgroundCallable->isThreadSafe(cPriv->loaderPrivate))
> @@ -215,34 +218,39 @@ dri_destroy_context(__DRIcontext * cPriv)
>      /* No particular reason to wait for command completion before
>       * destroying a context, but we flush the context here
>       * to avoid having to add code elsewhere to cope with flushing a
>       * partially destroyed context.
>       */
>      ctx->st->flush(ctx->st, 0, NULL);
>      ctx->st->destroy(ctx->st);
>      free(ctx);
>   }
>   
> +/* This is called inside MakeCurrent to unbind the context. */
>   GLboolean
>   dri_unbind_context(__DRIcontext * cPriv)
>   {
>      /* dri_util.c ensures cPriv is not null */
>      struct dri_screen *screen = dri_screen(cPriv->driScreenPriv);
>      struct dri_context *ctx = dri_context(cPriv);
>      struct st_context_iface *st = ctx->st;
>      struct st_api *stapi = screen->st_api;
>   
>      if (--ctx->bind_count == 0) {
>         if (st == stapi->get_current(stapi)) {
>            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);
>         }
>      }
>   
>      return GL_TRUE;
>   }
>   
>   GLboolean
>   dri_make_current(__DRIcontext * cPriv,
>   		 __DRIdrawable * driDrawPriv,
> 


-- 
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.


More information about the mesa-dev mailing list