From 33faf339c3de8e70dcef5240f9e88e1e2bde3713 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 8 Oct 2018 15:33:02 -0400 Subject: freedreno/msm: support suballocation for stateobj rb's Signed-off-by: Rob Clark --- freedreno/freedreno_ringbuffer.h | 14 +++++++ freedreno/msm/msm_pipe.c | 6 +++ freedreno/msm/msm_priv.h | 11 +++++ freedreno/msm/msm_ringbuffer.c | 88 ++++++++++++++++++++++++++++++++-------- 4 files changed, 101 insertions(+), 18 deletions(-) (limited to 'freedreno') 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; } -- cgit v1.2.1