[Mesa-dev] [PATCH 10/10] gallium/u_threaded: don't run out of memory with staging uploads

Dieter Nützel Dieter at nuetzel-hh.de
Thu Jan 11 03:42:16 UTC 2018


For the series:

Tested-by: Dieter Nützel <Dieter at nuetzel-hh.de>

on RX580 with UH, UV, glmark2 and Blender 2.79 with and without nir.

Dieter

Am 10.01.2018 20:49, schrieb Marek Olšák:
> From: Marek Olšák <marek.olsak at amd.com>
> 
> Cc: 17.2 17.3 <mesa-stable at lists.freedesktop.org>
> ---
>  src/gallium/auxiliary/util/u_threaded_context.c | 13 +++++++++++++
>  src/gallium/auxiliary/util/u_threaded_context.h |  8 ++++++++
>  2 files changed, 21 insertions(+)
> 
> diff --git a/src/gallium/auxiliary/util/u_threaded_context.c
> b/src/gallium/auxiliary/util/u_threaded_context.c
> index ffa8247..7bd13cf 100644
> --- a/src/gallium/auxiliary/util/u_threaded_context.c
> +++ b/src/gallium/auxiliary/util/u_threaded_context.c
> @@ -1508,35 +1508,47 @@ struct tc_resource_copy_region {
>  };
> 
>  static void
>  tc_resource_copy_region(struct pipe_context *_pipe,
>                          struct pipe_resource *dst, unsigned dst_level,
>                          unsigned dstx, unsigned dsty, unsigned dstz,
>                          struct pipe_resource *src, unsigned src_level,
>                          const struct pipe_box *src_box);
> 
>  static void
> +tc_notify_staging_upload_done(struct threaded_context *tc, unsigned 
> size)
> +{
> +   tc->unflushed_transfer_size += size;
> +
> +   if (tc->unflushed_transfer_size > 
> TC_MAX_UNFLUSHED_STAGING_UPLOAD_SIZE) {
> +      tc->base.flush(&tc->base, NULL, PIPE_FLUSH_ASYNC);
> +      tc->unflushed_transfer_size = 0;
> +   }
> +}
> +
> +static void
>  tc_buffer_do_flush_region(struct threaded_context *tc,
>                            struct threaded_transfer *ttrans,
>                            const struct pipe_box *box)
>  {
>     struct threaded_resource *tres = 
> threaded_resource(ttrans->b.resource);
> 
>     if (ttrans->staging) {
>        struct pipe_box src_box;
> 
>        u_box_1d(ttrans->offset + box->x % tc->map_buffer_alignment,
>                 box->width, &src_box);
> 
>        /* Copy the staging buffer into the original one. */
>        tc_resource_copy_region(&tc->base, ttrans->b.resource, 0, 
> box->x, 0, 0,
>                                ttrans->staging, 0, &src_box);
> +      tc_notify_staging_upload_done(tc, box->width);
>     }
> 
>     util_range_add(tres->base_valid_buffer_range, box->x, box->x + 
> box->width);
>  }
> 
>  static void
>  tc_transfer_flush_region(struct pipe_context *_pipe,
>                           struct pipe_transfer *transfer,
>                           const struct pipe_box *rel_box)
>  {
> @@ -1653,20 +1665,21 @@ tc_buffer_subdata(struct pipe_context *_pipe,
> 
>     /* The upload is small. Enqueue it. */
>     struct tc_buffer_subdata *p =
>        tc_add_slot_based_call(tc, TC_CALL_buffer_subdata,
> tc_buffer_subdata, size);
> 
>     tc_set_resource_reference(&p->resource, resource);
>     p->usage = usage;
>     p->offset = offset;
>     p->size = size;
>     memcpy(p->slot, data, size);
> +   tc_notify_staging_upload_done(tc, size);
>  }
> 
>  struct tc_texture_subdata {
>     struct pipe_resource *resource;
>     unsigned level, usage, stride, layer_stride;
>     struct pipe_box box;
>     char slot[0]; /* more will be allocated if needed */
>  };
> 
>  static void
> diff --git a/src/gallium/auxiliary/util/u_threaded_context.h
> b/src/gallium/auxiliary/util/u_threaded_context.h
> index 53c5a7e..295464a 100644
> --- a/src/gallium/auxiliary/util/u_threaded_context.h
> +++ b/src/gallium/auxiliary/util/u_threaded_context.h
> @@ -225,20 +225,27 @@ struct tc_unflushed_batch_token;
>  /* Threshold for when to use the queue or sync. */
>  #define TC_MAX_STRING_MARKER_BYTES  512
> 
>  /* Threshold for when to enqueue buffer/texture_subdata as-is.
>   * If the upload size is greater than this, it will do instead:
>   * - for buffers: DISCARD_RANGE is done by the threaded context
>   * - for textures: sync and call the driver directly
>   */
>  #define TC_MAX_SUBDATA_BYTES        320
> 
> +/* Every staging upload allocates memory. If we have too many uploads
> + * in a row without flushes, we might run out of memory. This limit 
> controls
> + * how many bytes of queued uploads we can have at a time. If we go 
> over,
> + * the threaded context triggers a context flush.
> + */
> +#define TC_MAX_UNFLUSHED_STAGING_UPLOAD_SIZE (512 * 1024 * 1024)
> +
>  typedef void (*tc_replace_buffer_storage_func)(struct pipe_context 
> *ctx,
>                                                 struct pipe_resource 
> *dst,
>                                                 struct pipe_resource 
> *src);
>  typedef struct pipe_fence_handle *(*tc_create_fence_func)(struct
> pipe_context *ctx,
>                                                            struct
> tc_unflushed_batch_token *token);
> 
>  struct threaded_resource {
>     struct pipe_resource b;
>     const struct u_resource_vtbl *vtbl;
> 
> @@ -346,20 +353,21 @@ struct tc_batch {
>     struct tc_call call[TC_CALLS_PER_BATCH];
>  };
> 
>  struct threaded_context {
>     struct pipe_context base;
>     struct pipe_context *pipe;
>     struct slab_child_pool pool_transfers;
>     tc_replace_buffer_storage_func replace_buffer_storage;
>     tc_create_fence_func create_fence;
>     unsigned map_buffer_alignment;
> +   unsigned unflushed_transfer_size;
> 
>     struct list_head unflushed_queries;
> 
>     /* Counters for the HUD. */
>     unsigned num_offloaded_slots;
>     unsigned num_direct_slots;
>     unsigned num_syncs;
> 
>     struct util_queue queue;
>     struct util_queue_fence *fence;


More information about the mesa-dev mailing list