[Mesa-dev] [PATCH 10/10] gallium/u_threaded: don't run out of memory with staging uploads
Marek Olšák
maraeo at gmail.com
Wed Jan 10 19:49:34 UTC 2018
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;
--
2.7.4
More information about the mesa-dev
mailing list