[Mesa-dev] [PATCH v3 51/63] radeonsi: add a slab allocator for bindless descriptors

Samuel Pitoiset samuel.pitoiset at gmail.com
Fri Jun 9 13:35:49 UTC 2017


For each texture/image handles, we need to allocate a new
buffer for the bindless descriptor. But when the number of
buffers added to the current CS becomes high, the overhead
in the winsys (and in the kernel) is important.

To reduce this bottleneck, the idea is to suballocate the
bindless descriptors using a slab similar to the one used
in the winsys.

Currently, a buffer can hold 1024 bindless descriptors but
this limit is arbitrary and could be changed in the future
for some reasons. Once a slab is allocated the "base" buffer
is added to a per-context list.

v3: - use PIPE_USAGE_DEFAULT instead of PIPE_USAGE_IMMUTABLE
    - replace util_dynarray_delete by util_dynarray_delete_unordered
v2: - rename si_resident_descriptor to si_bindless_descriptor
    - make can_reclaim_slab() returns false, always
    - use util_dynarray_*

Signed-off-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
Reviewed-by: Marek Olšák <marek.olsak at amd.com> (v2)
---
 src/gallium/drivers/radeonsi/si_descriptors.c | 84 +++++++++++++++++++++++++++
 src/gallium/drivers/radeonsi/si_pipe.c        | 12 ++++
 src/gallium/drivers/radeonsi/si_pipe.h        | 15 +++++
 src/gallium/drivers/radeonsi/si_state.h       |  8 +++
 4 files changed, 119 insertions(+)

diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
index ec19561fc0..16ffdef95e 100644
--- a/src/gallium/drivers/radeonsi/si_descriptors.c
+++ b/src/gallium/drivers/radeonsi/si_descriptors.c
@@ -2037,6 +2037,90 @@ void si_emit_compute_shader_userdata(struct si_context *sctx)
 	sctx->shader_pointers_dirty &= ~compute_mask;
 }
 
+/* BINDLESS */
+
+struct si_bindless_descriptor_slab
+{
+	struct pb_slab base;
+	struct r600_resource *buffer;
+	struct si_bindless_descriptor *entries;
+};
+
+bool si_bindless_descriptor_can_reclaim_slab(void *priv,
+					     struct pb_slab_entry *entry)
+{
+	/* Do not allow to reclaim any bindless descriptors for now because the
+	 * GPU might be using them. This should be improved later on.
+	 */
+	return false;
+}
+
+struct pb_slab *si_bindless_descriptor_slab_alloc(void *priv, unsigned heap,
+						  unsigned entry_size,
+						  unsigned group_index)
+{
+	struct si_context *sctx = priv;
+	struct si_screen *sscreen = sctx->screen;
+	struct si_bindless_descriptor_slab *slab;
+
+	slab = CALLOC_STRUCT(si_bindless_descriptor_slab);
+	if (!slab)
+		return NULL;
+
+	/* Create a buffer in VRAM for 1024 bindless descriptors. */
+	slab->buffer = (struct r600_resource *)
+		pipe_buffer_create(&sscreen->b.b, 0,
+				   PIPE_USAGE_DEFAULT, 64 * 1024);
+	if (!slab->buffer)
+		goto fail;
+
+	slab->base.num_entries = slab->buffer->bo_size / entry_size;
+	slab->base.num_free = slab->base.num_entries;
+	slab->entries = CALLOC(slab->base.num_entries, sizeof(*slab->entries));
+	if (!slab->entries)
+		goto fail_buffer;
+
+	LIST_INITHEAD(&slab->base.free);
+
+	for (unsigned i = 0; i < slab->base.num_entries; ++i) {
+		struct si_bindless_descriptor *desc = &slab->entries[i];
+
+		desc->entry.slab = &slab->base;
+		desc->entry.group_index = group_index;
+		desc->buffer = slab->buffer;
+		desc->offset = i * entry_size;
+
+		LIST_ADDTAIL(&desc->entry.head, &slab->base.free);
+	}
+
+	/* Add the descriptor to the per-context list. */
+	util_dynarray_append(&sctx->bindless_descriptors,
+			    struct r600_resource *, slab->buffer);
+
+	return &slab->base;
+
+fail_buffer:
+	r600_resource_reference(&slab->buffer, NULL);
+fail:
+	FREE(slab);
+	return NULL;
+}
+
+void si_bindless_descriptor_slab_free(void *priv, struct pb_slab *pslab)
+{
+	struct si_context *sctx = priv;
+	struct si_bindless_descriptor_slab *slab =
+		(struct si_bindless_descriptor_slab *)pslab;
+
+	/* Remove the descriptor from the per-context list. */
+	util_dynarray_delete_unordered(&sctx->bindless_descriptors,
+				       struct r600_resource *, slab->buffer);
+
+	r600_resource_reference(&slab->buffer, NULL);
+	FREE(slab->entries);
+	FREE(slab);
+}
+
 /* INIT/DEINIT/UPLOAD */
 
 /* GFX9 has only 4KB of CE, while previous chips had 32KB. In order
diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c
index 031e4731bf..14fe9dd6a3 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.c
+++ b/src/gallium/drivers/radeonsi/si_pipe.c
@@ -94,6 +94,9 @@ static void si_destroy_context(struct pipe_context *context)
 	r600_resource_reference(&sctx->last_trace_buf, NULL);
 	radeon_clear_saved_cs(&sctx->last_gfx);
 
+	pb_slabs_deinit(&sctx->bindless_descriptor_slabs);
+	util_dynarray_fini(&sctx->bindless_descriptors);
+
 	FREE(sctx);
 }
 
@@ -316,6 +319,15 @@ static struct pipe_context *si_create_context(struct pipe_screen *screen,
 
 	sctx->tm = si_create_llvm_target_machine(sscreen);
 
+	/* Create a slab allocator for all bindless descriptors. */
+	if (!pb_slabs_init(&sctx->bindless_descriptor_slabs, 6, 6, 1, sctx,
+			   si_bindless_descriptor_can_reclaim_slab,
+			   si_bindless_descriptor_slab_alloc,
+			   si_bindless_descriptor_slab_free))
+		goto fail;
+
+	util_dynarray_init(&sctx->bindless_descriptors, NULL);
+
 	return &sctx->b.b;
 fail:
 	fprintf(stderr, "radeonsi: Failed to create a context.\n");
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index b5c77973cc..6260c95fe5 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -28,6 +28,8 @@
 
 #include "si_shader.h"
 
+#include "util/u_dynarray.h"
+
 #ifdef PIPE_ARCH_BIG_ENDIAN
 #define SI_BIG_ENDIAN 1
 #else
@@ -228,6 +230,13 @@ union si_vgt_param_key {
 	uint32_t index;
 };
 
+struct si_bindless_descriptor
+{
+	struct pb_slab_entry		entry;
+	struct r600_resource		*buffer;
+	unsigned			offset;
+};
+
 struct si_context {
 	struct r600_common_context	b;
 	struct blitter_context		*blitter;
@@ -390,6 +399,12 @@ struct si_context {
 	/* Precomputed IA_MULTI_VGT_PARAM */
 	union si_vgt_param_key  ia_multi_vgt_param_key;
 	unsigned		ia_multi_vgt_param[SI_NUM_VGT_PARAM_STATES];
+
+	/* Slab allocator for bindless descriptors. */
+	struct pb_slabs		bindless_descriptor_slabs;
+
+	/* Bindless descriptors. */
+	struct util_dynarray	bindless_descriptors;
 };
 
 /* cik_sdma.c */
diff --git a/src/gallium/drivers/radeonsi/si_state.h b/src/gallium/drivers/radeonsi/si_state.h
index 4da51be3ea..612c49fb0e 100644
--- a/src/gallium/drivers/radeonsi/si_state.h
+++ b/src/gallium/drivers/radeonsi/si_state.h
@@ -30,6 +30,8 @@
 #include "si_pm4.h"
 #include "radeon/r600_pipe_common.h"
 
+#include "pipebuffer/pb_slab.h"
+
 #define SI_NUM_GRAPHICS_SHADERS (PIPE_SHADER_TESS_EVAL+1)
 #define SI_NUM_SHADERS (PIPE_SHADER_COMPUTE+1)
 
@@ -336,6 +338,12 @@ void si_set_active_descriptors(struct si_context *sctx, unsigned desc_idx,
 			       uint64_t new_active_mask);
 void si_set_active_descriptors_for_shader(struct si_context *sctx,
 					  struct si_shader_selector *sel);
+bool si_bindless_descriptor_can_reclaim_slab(void *priv,
+					     struct pb_slab_entry *entry);
+struct pb_slab *si_bindless_descriptor_slab_alloc(void *priv, unsigned heap,
+						  unsigned entry_size,
+						  unsigned group_index);
+void si_bindless_descriptor_slab_free(void *priv, struct pb_slab *pslab);
 
 /* si_state.c */
 struct si_shader_selector;
-- 
2.13.1



More information about the mesa-dev mailing list