freedreno/msm: support suballocation for stateobj rb's

Signed-off-by: Rob Clark <robclark@freedesktop.org>
main
Rob Clark 2018-10-08 15:33:02 -04:00
parent bf001648a9
commit 33faf339c3
4 changed files with 101 additions and 18 deletions

View File

@ -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 {

View File

@ -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);
}

View File

@ -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)

View File

@ -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;
}