Module: Mesa
Branch: main
Commit: 542585556275298779c29ac618dc50b2d9353279
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=542585556275298779c29ac618dc50b2d9353279

Author: Boris Brezillon <[email protected]>
Date:   Wed May 12 16:17:57 2021 +0200

panfrost: Limit the number of active batch to 32

Should improve memory usage at the expense of more agressive batch
submission when the free batch pool is empty. The limit has been chosen
such that a batches bitmap fits nicely in a 32-bit integer.

Signed-off-by: Boris Brezillon <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10842>

---

 src/gallium/drivers/panfrost/pan_context.c |   4 +-
 src/gallium/drivers/panfrost/pan_context.h |  13 +++-
 src/gallium/drivers/panfrost/pan_job.c     | 104 ++++++++++++-----------------
 src/gallium/drivers/panfrost/pan_job.h     |   6 +-
 4 files changed, 60 insertions(+), 67 deletions(-)

diff --git a/src/gallium/drivers/panfrost/pan_context.c 
b/src/gallium/drivers/panfrost/pan_context.c
index 29d533355d7..09c90ef63ce 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -1874,7 +1874,9 @@ panfrost_create_context(struct pipe_screen *screen, void 
*priv, unsigned flags)
 
         /* Prepare for render! */
 
-        panfrost_batch_init(ctx);
+        ctx->accessed_bos =
+                _mesa_hash_table_create(ctx, _mesa_hash_pointer,
+                                        _mesa_key_pointer_equal);
 
         /* By default mask everything on */
         ctx->sample_mask = ~0;
diff --git a/src/gallium/drivers/panfrost/pan_context.h 
b/src/gallium/drivers/panfrost/pan_context.h
index b7eb0b0d8ad..08658e41de7 100644
--- a/src/gallium/drivers/panfrost/pan_context.h
+++ b/src/gallium/drivers/panfrost/pan_context.h
@@ -100,6 +100,8 @@ struct panfrost_streamout {
         unsigned num_targets;
 };
 
+#define PAN_MAX_BATCHES 32
+
 struct panfrost_context {
         /* Gallium context */
         struct pipe_context base;
@@ -112,9 +114,16 @@ struct panfrost_context {
         /* Sync obj used to keep track of in-flight jobs. */
         uint32_t syncobj;
 
-        /* Bound job batch and map of panfrost_batch_key to job batches */
+        /* Set of 32 batches. When the set is full, the LRU entry (the batch
+         * with the smallest seqnum) is flushed to free a slot.
+         */
+        struct {
+                uint64_t seqnum;
+                struct panfrost_batch slots[PAN_MAX_BATCHES];
+        } batches;
+
+        /* Bound job batch */
         struct panfrost_batch *batch;
-        struct hash_table *batches;
 
         /* panfrost_bo -> panfrost_bo_access */
         struct hash_table *accessed_bos;
diff --git a/src/gallium/drivers/panfrost/pan_job.c 
b/src/gallium/drivers/panfrost/pan_job.c
index 979a768cd7e..e5daa77704a 100644
--- a/src/gallium/drivers/panfrost/pan_job.c
+++ b/src/gallium/drivers/panfrost/pan_job.c
@@ -64,16 +64,18 @@ struct panfrost_bo_access {
         bool last_is_write;
 };
 
-static struct panfrost_batch *
-panfrost_create_batch(struct panfrost_context *ctx,
-                      const struct pipe_framebuffer_state *key)
+static void
+panfrost_batch_init(struct panfrost_context *ctx,
+                    const struct pipe_framebuffer_state *key,
+                    struct panfrost_batch *batch)
 {
-        struct panfrost_batch *batch = rzalloc(ctx, struct panfrost_batch);
         struct panfrost_device *dev = pan_device(ctx->base.screen);
 
         batch->ctx = ctx;
 
-        batch->bos = _mesa_hash_table_create(batch, _mesa_hash_pointer,
+        batch->seqnum = ++ctx->batches.seqnum;
+
+        batch->bos = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
                         _mesa_key_pointer_equal);
 
         batch->minx = batch->miny = ~0;
@@ -83,34 +85,25 @@ panfrost_create_batch(struct panfrost_context *ctx,
 
         /* Preallocate the main pool, since every batch has at least one job
          * structure so it will be used */
-        panfrost_pool_init(&batch->pool, batch, dev, 0, true);
+        panfrost_pool_init(&batch->pool, NULL, dev, 0, true);
 
         /* Don't preallocate the invisible pool, since not every batch will use
          * the pre-allocation, particularly if the varyings are larger than the
          * preallocation and a reallocation is needed after anyway. */
-        panfrost_pool_init(&batch->invisible_pool, batch, dev, 
PAN_BO_INVISIBLE, false);
+        panfrost_pool_init(&batch->invisible_pool, NULL, dev, 
PAN_BO_INVISIBLE, false);
 
         panfrost_batch_add_fbo_bos(batch);
-
-        return batch;
 }
 
 static void
-panfrost_free_batch(struct panfrost_batch *batch)
+panfrost_batch_cleanup(struct panfrost_batch *batch)
 {
         if (!batch)
                 return;
 
         struct panfrost_context *ctx = batch->ctx;
 
-        /* Remove the entry in the FBO -> batch hash table if the batch
-         * matches and drop the context reference. This way, next draws/clears
-         * targeting this FBO will trigger the creation of a new batch.
-         */
-        struct hash_entry *batch_entry =
-                _mesa_hash_table_search(ctx->batches, &batch->key);
-        if (batch_entry && batch_entry->data == batch)
-                _mesa_hash_table_remove(ctx->batches, batch_entry);
+        assert(batch->seqnum);
 
         if (ctx->batch == batch)
                 ctx->batch = NULL;
@@ -152,33 +145,46 @@ panfrost_free_batch(struct panfrost_batch *batch)
 
         util_unreference_framebuffer_state(&batch->key);
 
-        ralloc_free(batch);
+        _mesa_hash_table_destroy(batch->bos, NULL);
+
+        memset(batch, 0, sizeof(*batch));
 }
 
+static void
+panfrost_batch_submit(struct panfrost_batch *batch,
+                      uint32_t in_sync, uint32_t out_sync);
+
 static struct panfrost_batch *
 panfrost_get_batch(struct panfrost_context *ctx,
                    const struct pipe_framebuffer_state *key)
 {
-        /* Lookup the job first */
-        struct hash_entry *entry = _mesa_hash_table_search(ctx->batches, key);
+        struct panfrost_batch *batch = NULL;
+
+        for (unsigned i = 0; i < PAN_MAX_BATCHES; i++) {
+                if (ctx->batches.slots[i].seqnum &&
+                    util_framebuffer_state_equal(&ctx->batches.slots[i].key, 
key)) {
+                        /* We found a match, increase the seqnum for the LRU
+                         * eviction logic.
+                         */
+                        ctx->batches.slots[i].seqnum = ++ctx->batches.seqnum;
+                        return &ctx->batches.slots[i];
+                }
 
-        if (entry)
-                return entry->data;
+                if (!batch || batch->seqnum > ctx->batches.slots[i].seqnum)
+                        batch = &ctx->batches.slots[i];
+        }
 
-        /* Otherwise, let's create a job */
+        assert(batch);
 
-        struct panfrost_batch *batch = panfrost_create_batch(ctx, key);
+        /* The selected slot is used, we need to flush the batch */
+        if (batch->seqnum)
+                panfrost_batch_submit(batch, 0, 0);
 
-        /* Save the created job */
-        _mesa_hash_table_insert(ctx->batches, &batch->key, batch);
+        panfrost_batch_init(ctx, key, batch);
 
         return batch;
 }
 
-static void
-panfrost_batch_submit(struct panfrost_batch *batch,
-                      uint32_t in_sync, uint32_t out_sync);
-
 struct panfrost_batch *
 panfrost_get_fresh_batch(struct panfrost_context *ctx,
                          const struct pipe_framebuffer_state *key)
@@ -995,7 +1001,7 @@ panfrost_batch_submit(struct panfrost_batch *batch,
         }
 
 out:
-        panfrost_free_batch(batch);
+        panfrost_batch_cleanup(batch);
 }
 
 /* Submit all batches, applying the out_sync to the currently bound batch */
@@ -1006,14 +1012,12 @@ panfrost_flush_all_batches(struct panfrost_context *ctx)
         struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
         panfrost_batch_submit(batch, ctx->syncobj, ctx->syncobj);
 
-        hash_table_foreach(ctx->batches, hentry) {
-                struct panfrost_batch *batch = hentry->data;
-                assert(batch);
-
-                panfrost_batch_submit(batch, ctx->syncobj, ctx->syncobj);
+        for (unsigned i = 0; i < PAN_MAX_BATCHES; i++) {
+                if (ctx->batches.slots[i].seqnum) {
+                        panfrost_batch_submit(&ctx->batches.slots[i],
+                                              ctx->syncobj, ctx->syncobj);
+                }
         }
-
-        assert(!ctx->batches->entries);
 }
 
 bool
@@ -1229,18 +1233,6 @@ panfrost_batch_clear(struct panfrost_batch *batch,
                                      ctx->pipe_framebuffer.height);
 }
 
-static bool
-panfrost_batch_compare(const void *a, const void *b)
-{
-        return util_framebuffer_state_equal(a, b);
-}
-
-static uint32_t
-panfrost_batch_hash(const void *key)
-{
-        return _mesa_hash_data(key, sizeof(struct pipe_framebuffer_state));
-}
-
 /* Given a new bounding rectangle (scissor), let the job cover the union of the
  * new and old bounding rectangles */
 
@@ -1265,13 +1257,3 @@ panfrost_batch_intersection_scissor(struct 
panfrost_batch *batch,
         batch->maxx = MIN2(batch->maxx, maxx);
         batch->maxy = MIN2(batch->maxy, maxy);
 }
-
-void
-panfrost_batch_init(struct panfrost_context *ctx)
-{
-        ctx->batches = _mesa_hash_table_create(ctx,
-                                               panfrost_batch_hash,
-                                               panfrost_batch_compare);
-        ctx->accessed_bos = _mesa_hash_table_create(ctx, _mesa_hash_pointer,
-                                                    _mesa_key_pointer_equal);
-}
diff --git a/src/gallium/drivers/panfrost/pan_job.h 
b/src/gallium/drivers/panfrost/pan_job.h
index b3798381251..8ede7da7642 100644
--- a/src/gallium/drivers/panfrost/pan_job.h
+++ b/src/gallium/drivers/panfrost/pan_job.h
@@ -40,6 +40,9 @@ struct panfrost_batch {
         struct panfrost_context *ctx;
         struct pipe_framebuffer_state key;
 
+        /* Sequence number used to implement LRU eviction when all batch slots 
are used */
+        uint64_t seqnum;
+
         /* Buffers cleared (PIPE_CLEAR_* bitmask) */
         unsigned clear;
 
@@ -125,9 +128,6 @@ panfrost_get_batch_for_fbo(struct panfrost_context *ctx);
 struct panfrost_batch *
 panfrost_get_fresh_batch_for_fbo(struct panfrost_context *ctx);
 
-void
-panfrost_batch_init(struct panfrost_context *ctx);
-
 void
 panfrost_batch_add_bo(struct panfrost_batch *batch, struct panfrost_bo *bo,
                       uint32_t flags);

_______________________________________________
mesa-commit mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-commit

Reply via email to