[Mesa-dev] [PATCH 6/6] radeonsi: try to re-use previously deleted bindless descriptor slots

Samuel Pitoiset samuel.pitoiset at gmail.com
Tue Jul 4 13:05:57 UTC 2017


Currently, when the array is full it is resized but it can grow
over and over because we don't try to re-use descriptor slots.

The idea is to maintain two simple lists which keep track of
which slots is used and which ones have been deleted. When the
array is resized, previously deleted slots can be marked as
free because we are going to upload a new fresh buffer.

Signed-off-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
---
 src/gallium/drivers/radeonsi/si_descriptors.c | 85 +++++++++++++++++++++++----
 src/gallium/drivers/radeonsi/si_pipe.h        |  2 +
 2 files changed, 75 insertions(+), 12 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
index 601b18069d..5756d111af 100644
--- a/src/gallium/drivers/radeonsi/si_descriptors.c
+++ b/src/gallium/drivers/radeonsi/si_descriptors.c
@@ -2298,11 +2298,72 @@ static void si_init_bindless_descriptors(struct si_context *sctx,
 	 * considered to be a valid handle.
 	 */
 	sctx->num_bindless_descriptors = 1;
+
+	/* Allocate two simple arrays for re-using previously deleted slots. */
+	sctx->bindless_used_slots = CALLOC(num_elements, sizeof(bool));
+	sctx->bindless_free_slots = CALLOC(num_elements, sizeof(bool));
 }
 
 static void si_release_bindless_descriptors(struct si_context *sctx)
 {
 	si_release_descriptors(&sctx->bindless_descriptors);
+	FREE(sctx->bindless_used_slots);
+	FREE(sctx->bindless_free_slots);
+}
+
+static unsigned si_get_next_free_bindless_slot(struct si_context *sctx)
+{
+	struct si_descriptors *desc = &sctx->bindless_descriptors;
+	unsigned i;
+
+	for (i = 1; i < desc->num_elements; i++) {
+		if (!sctx->bindless_used_slots[i]) {
+			/* Lock this descriptor slot. */
+			sctx->bindless_used_slots[i] = true;
+			return i;
+		}
+	}
+
+	/* No available descriptor slots. */
+	return 0;
+}
+
+static void si_resize_bindless_descriptor(struct si_context *sctx)
+{
+	struct si_descriptors *desc = &sctx->bindless_descriptors;
+	unsigned slot_size = desc->element_dw_size * 4;
+	unsigned old_num_elements = desc->num_elements;
+	unsigned new_num_elements = old_num_elements * 2;
+	unsigned i;
+
+	/* All previously deleted slots can now be re-used because we are going
+	 * to upload a new buffer.
+	 */
+	for (i = 1; i < old_num_elements; i++) {
+		if (sctx->bindless_free_slots[i]) {
+			/* Unlock this descriptor slot. */
+			sctx->bindless_used_slots[i] = false;
+		}
+		sctx->bindless_free_slots[i] = false;
+	}
+
+	/* Resize the array of descriptors. */
+	desc->list = REALLOC(desc->list, desc->num_elements * slot_size,
+			     new_num_elements * slot_size);
+	desc->num_elements = new_num_elements;
+	desc->num_active_slots = new_num_elements;
+
+	/* Resize the two simple arrays and mark all slots as free. */
+	sctx->bindless_used_slots = REALLOC(sctx->bindless_used_slots,
+					    old_num_elements,
+					    new_num_elements);
+	sctx->bindless_free_slots = REALLOC(sctx->bindless_free_slots,
+					    old_num_elements,
+					    new_num_elements);
+	for (i = old_num_elements; i < new_num_elements; i++) {
+		sctx->bindless_used_slots[i] = false;
+		sctx->bindless_free_slots[i] = false;
+	}
 }
 
 static unsigned
@@ -2314,19 +2375,16 @@ si_create_bindless_descriptor(struct si_context *sctx, uint32_t *desc_list,
 	bool resized = false;
 	unsigned desc_slot;
 
-	/* Reserve a new slot for this bindless descriptor. */
-	desc_slot = sctx->num_bindless_descriptors++;
-
-	if (desc_slot >= desc->num_elements) {
-		/* The array of bindless descriptors is full, resize it. */
-		unsigned slot_size = desc->element_dw_size * 4;
-		unsigned new_num_elements = desc->num_elements * 2;
-
-		desc->list = REALLOC(desc->list, desc->num_elements * slot_size,
-				     new_num_elements * slot_size);
-		desc->num_elements = new_num_elements;
-		desc->num_active_slots = new_num_elements;
+	/* Find a free slot. */
+	desc_slot = si_get_next_free_bindless_slot(sctx);
+	if (!desc_slot) {
+		/* The array of descriptors is full, resize it. */
+		si_resize_bindless_descriptor(sctx);
 		resized = true;
+
+		/* Get a new slot. */
+		desc_slot = si_get_next_free_bindless_slot(sctx);
+		assert(desc_slot);
 	}
 
 	/* Copy the descriptor into the array. */
@@ -2452,6 +2510,9 @@ static void si_delete_texture_handle(struct pipe_context *ctx, uint64_t handle)
 
 	tex_handle = (struct si_texture_handle *)entry->data;
 
+	/* Mark this descriptor slot as free in order to re-use it. */
+	sctx->bindless_free_slots[tex_handle->desc_slot] = true;
+
 	pipe_sampler_view_reference(&tex_handle->view, NULL);
 	_mesa_hash_table_remove(sctx->tex_handles, entry);
 	FREE(tex_handle);
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 819a44d226..869adadb91 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -413,6 +413,8 @@ struct si_context {
 
 	/* Bindless descriptors. */
 	struct si_descriptors	bindless_descriptors;
+	bool			*bindless_used_slots;
+	bool			*bindless_free_slots;
 	unsigned		num_bindless_descriptors;
 	bool			bindless_descriptors_dirty;
 	bool			graphics_bindless_pointer_dirty;
-- 
2.13.2



More information about the mesa-dev mailing list