summaryrefslogtreecommitdiff
path: root/freedreno
diff options
context:
space:
mode:
authorRob Clark <robclark@freedesktop.org>2018-10-08 15:33:02 -0400
committerRob Clark <robclark@freedesktop.org>2018-10-13 17:21:53 -0400
commit33faf339c3de8e70dcef5240f9e88e1e2bde3713 (patch)
tree72d2761f8eca405a7b90ee4a0b9f47472914a401 /freedreno
parentbf001648a92c8f5e10d95322f486a346febd2c09 (diff)
downloaddrm-33faf339c3de8e70dcef5240f9e88e1e2bde3713.tar.gz
freedreno/msm: support suballocation for stateobj rb's
Signed-off-by: Rob Clark <robclark@freedesktop.org>
Diffstat (limited to 'freedreno')
-rw-r--r--freedreno/freedreno_ringbuffer.h14
-rw-r--r--freedreno/msm/msm_pipe.c6
-rw-r--r--freedreno/msm/msm_priv.h11
-rw-r--r--freedreno/msm/msm_ringbuffer.c88
4 files changed, 101 insertions, 18 deletions
diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h
index c5aebaf2..ad615e8f 100644
--- a/freedreno/freedreno_ringbuffer.h
+++ b/freedreno/freedreno_ringbuffer.h
@@ -46,6 +46,20 @@ enum fd_ringbuffer_flags {
* to a parent ringbuffer.
*/
FD_RINGBUFFER_OBJECT = 0x1,
+
+ /* Hint that the stateobj will be used for streaming state
+ * that is used once or a few times and then discarded.
+ *
+ * For sub-allocation, non streaming stateobj's should be
+ * sub-allocated from a page size buffer, so one long lived
+ * state obj doesn't prevent other pages from being freed.
+ * (Ie. it would be no worse than allocating a page sized
+ * bo for each small non-streaming stateobj).
+ *
+ * But streaming stateobj's could be sub-allocated from a
+ * larger buffer to reduce the alloc/del overhead.
+ */
+ FD_RINGBUFFER_STREAMING = 0x2,
};
struct fd_ringbuffer {
diff --git a/freedreno/msm/msm_pipe.c b/freedreno/msm/msm_pipe.c
index f28778ef..e070b317 100644
--- a/freedreno/msm/msm_pipe.c
+++ b/freedreno/msm/msm_pipe.c
@@ -138,6 +138,12 @@ static void msm_pipe_destroy(struct fd_pipe *pipe)
{
struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
close_submitqueue(pipe, msm_pipe->queue_id);
+
+ if (msm_pipe->suballoc_ring) {
+ fd_ringbuffer_del(msm_pipe->suballoc_ring);
+ msm_pipe->suballoc_ring = NULL;
+ }
+
free(msm_pipe);
}
diff --git a/freedreno/msm/msm_priv.h b/freedreno/msm/msm_priv.h
index ee0eecb8..cc951fba 100644
--- a/freedreno/msm/msm_priv.h
+++ b/freedreno/msm/msm_priv.h
@@ -57,6 +57,17 @@ struct msm_pipe {
uint32_t gmem;
uint32_t chip_id;
uint32_t queue_id;
+
+ /* Allow for sub-allocation of stateobj ring buffers (ie. sharing
+ * the same underlying bo)..
+ *
+ * This takes advantage of each context having it's own fd_pipe,
+ * so we don't have to worry about access from multiple threads.
+ *
+ * We also rely on previous stateobj having been fully constructed
+ * so we can reclaim extra space at it's end.
+ */
+ struct fd_ringbuffer *suballoc_ring;
};
static inline struct msm_pipe * to_msm_pipe(struct fd_pipe *x)
diff --git a/freedreno/msm/msm_ringbuffer.c b/freedreno/msm/msm_ringbuffer.c
index a102ca35..a9190886 100644
--- a/freedreno/msm/msm_ringbuffer.c
+++ b/freedreno/msm/msm_ringbuffer.c
@@ -85,6 +85,8 @@ struct msm_ringbuffer {
int is_growable;
unsigned cmd_count;
+ unsigned offset; /* for sub-allocated stateobj rb's */
+
unsigned seqno;
/* maps fd_bo to idx: */
@@ -100,6 +102,13 @@ static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x)
static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring)
+{
+ struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+ assert(!LIST_IS_EMPTY(&msm_ring->cmd_list));
+ return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list);
+}
+
static void ring_cmd_del(struct msm_cmd *cmd)
{
fd_bo_del(cmd->ring_bo);
@@ -109,7 +118,8 @@ static void ring_cmd_del(struct msm_cmd *cmd)
free(cmd);
}
-static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size)
+static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size,
+ enum fd_ringbuffer_flags flags)
{
struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
struct msm_cmd *cmd = calloc(1, sizeof(*cmd));
@@ -118,7 +128,48 @@ static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size)
return NULL;
cmd->ring = ring;
- cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, size, 0);
+
+ /* TODO separate suballoc buffer for small non-streaming state, using
+ * smaller page-sized backing bo's.
+ */
+ if (flags & FD_RINGBUFFER_STREAMING) {
+ struct msm_pipe *msm_pipe = to_msm_pipe(ring->pipe);
+ unsigned suballoc_offset = 0;
+ struct fd_bo *suballoc_bo = NULL;
+
+ if (msm_pipe->suballoc_ring) {
+ struct msm_ringbuffer *suballoc_ring = to_msm_ringbuffer(msm_pipe->suballoc_ring);
+
+ assert(msm_pipe->suballoc_ring->flags & FD_RINGBUFFER_OBJECT);
+ assert(suballoc_ring->cmd_count == 1);
+
+ suballoc_bo = current_cmd(msm_pipe->suballoc_ring)->ring_bo;
+
+ suballoc_offset = fd_ringbuffer_size(msm_pipe->suballoc_ring) +
+ suballoc_ring->offset;
+
+ suballoc_offset = ALIGN(suballoc_offset, 0x10);
+
+ if ((size + suballoc_offset) > suballoc_bo->size) {
+ suballoc_bo = NULL;
+ }
+ }
+
+ if (!suballoc_bo) {
+ cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, 0x8000, 0);
+ msm_ring->offset = 0;
+ } else {
+ cmd->ring_bo = fd_bo_ref(suballoc_bo);
+ msm_ring->offset = suballoc_offset;
+ }
+
+ if (msm_pipe->suballoc_ring)
+ fd_ringbuffer_del(msm_pipe->suballoc_ring);
+
+ msm_pipe->suballoc_ring = fd_ringbuffer_ref(ring);
+ } else {
+ cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, size, 0);
+ }
if (!cmd->ring_bo)
goto fail;
@@ -132,13 +183,6 @@ fail:
return NULL;
}
-static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring)
-{
- struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
- assert(!LIST_IS_EMPTY(&msm_ring->cmd_list));
- return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list);
-}
-
static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo)
{
struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
@@ -238,7 +282,9 @@ static int get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd,
static void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring)
{
- return fd_bo_map(current_cmd(ring)->ring_bo);
+ struct msm_cmd *cmd = current_cmd(ring);
+ uint8_t *base = fd_bo_map(cmd->ring_bo);
+ return base + to_msm_ringbuffer(ring)->offset;
}
static uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd,
@@ -374,9 +420,10 @@ static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start
int in_fence_fd, int *out_fence_fd)
{
struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+ struct msm_pipe *msm_pipe = to_msm_pipe(ring->pipe);
struct drm_msm_gem_submit req = {
- .flags = to_msm_pipe(ring->pipe)->pipe,
- .queueid = to_msm_pipe(ring->pipe)->queue_id,
+ .flags = msm_pipe->pipe,
+ .queueid = msm_pipe->queue_id,
};
uint32_t i;
int ret;
@@ -464,7 +511,7 @@ static void msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size)
{
assert(to_msm_ringbuffer(ring)->is_growable);
finalize_current_cmd(ring, ring->last_start);
- ring_cmd_new(ring, size);
+ ring_cmd_new(ring, size, 0);
}
static void msm_ringbuffer_reset(struct fd_ringbuffer *ring)
@@ -488,7 +535,8 @@ static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
reloc->reloc_offset = r->offset;
reloc->or = r->or;
reloc->shift = r->shift;
- reloc->submit_offset = offset_bytes(ring->cur, ring->start);
+ reloc->submit_offset = offset_bytes(ring->cur, ring->start) +
+ to_msm_ringbuffer(ring)->offset;
addr = msm_bo->presumed;
if (reloc->shift < 0)
@@ -513,7 +561,8 @@ static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
reloc_hi->reloc_offset = r->offset;
reloc_hi->or = r->orhi;
reloc_hi->shift = r->shift - 32;
- reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start);
+ reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start) +
+ to_msm_ringbuffer(ring)->offset;
addr = msm_bo->presumed >> 32;
if (reloc_hi->shift < 0)
@@ -529,10 +578,13 @@ static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
uint32_t submit_offset, uint32_t size)
{
struct msm_cmd *cmd = NULL;
+ struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target);
uint32_t idx = 0;
int added_cmd = FALSE;
- LIST_FOR_EACH_ENTRY(cmd, &to_msm_ringbuffer(target)->cmd_list, list) {
+ submit_offset += msm_target->offset;
+
+ LIST_FOR_EACH_ENTRY(cmd, &msm_target->cmd_list, list) {
if (idx == cmd_idx)
break;
idx++;
@@ -540,7 +592,7 @@ static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
assert(cmd && (idx == cmd_idx));
- if (idx < (to_msm_ringbuffer(target)->cmd_count - 1)) {
+ if (idx < (msm_target->cmd_count - 1)) {
/* All but the last cmd buffer is fully "baked" (ie. already has
* done get_cmd() to add it to the cmds table). But in this case,
* the size we get is invalid (since it is calculated from the
@@ -628,7 +680,7 @@ drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe,
ring->size = size;
ring->pipe = pipe; /* needed in ring_cmd_new() */
- ring_cmd_new(ring, size);
+ ring_cmd_new(ring, size, flags);
return ring;
}