freedreno/msm: support suballocation for stateobj rb's
Signed-off-by: Rob Clark <robclark@freedesktop.org>main
parent
bf001648a9
commit
33faf339c3
|
@ -46,6 +46,20 @@ enum fd_ringbuffer_flags {
|
||||||
* to a parent ringbuffer.
|
* to a parent ringbuffer.
|
||||||
*/
|
*/
|
||||||
FD_RINGBUFFER_OBJECT = 0x1,
|
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 {
|
struct fd_ringbuffer {
|
||||||
|
|
|
@ -138,6 +138,12 @@ static void msm_pipe_destroy(struct fd_pipe *pipe)
|
||||||
{
|
{
|
||||||
struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
|
struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
|
||||||
close_submitqueue(pipe, msm_pipe->queue_id);
|
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);
|
free(msm_pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,17 @@ struct msm_pipe {
|
||||||
uint32_t gmem;
|
uint32_t gmem;
|
||||||
uint32_t chip_id;
|
uint32_t chip_id;
|
||||||
uint32_t queue_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)
|
static inline struct msm_pipe * to_msm_pipe(struct fd_pipe *x)
|
||||||
|
|
|
@ -85,6 +85,8 @@ struct msm_ringbuffer {
|
||||||
int is_growable;
|
int is_growable;
|
||||||
unsigned cmd_count;
|
unsigned cmd_count;
|
||||||
|
|
||||||
|
unsigned offset; /* for sub-allocated stateobj rb's */
|
||||||
|
|
||||||
unsigned seqno;
|
unsigned seqno;
|
||||||
|
|
||||||
/* maps fd_bo to idx: */
|
/* 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 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)
|
static void ring_cmd_del(struct msm_cmd *cmd)
|
||||||
{
|
{
|
||||||
fd_bo_del(cmd->ring_bo);
|
fd_bo_del(cmd->ring_bo);
|
||||||
|
@ -109,7 +118,8 @@ static void ring_cmd_del(struct msm_cmd *cmd)
|
||||||
free(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_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
|
||||||
struct msm_cmd *cmd = calloc(1, sizeof(*cmd));
|
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;
|
return NULL;
|
||||||
|
|
||||||
cmd->ring = ring;
|
cmd->ring = ring;
|
||||||
|
|
||||||
|
/* 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);
|
cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, size, 0);
|
||||||
|
}
|
||||||
if (!cmd->ring_bo)
|
if (!cmd->ring_bo)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -132,13 +183,6 @@ fail:
|
||||||
return NULL;
|
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)
|
static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo)
|
||||||
{
|
{
|
||||||
struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
|
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)
|
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,
|
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)
|
int in_fence_fd, int *out_fence_fd)
|
||||||
{
|
{
|
||||||
struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
|
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 = {
|
struct drm_msm_gem_submit req = {
|
||||||
.flags = to_msm_pipe(ring->pipe)->pipe,
|
.flags = msm_pipe->pipe,
|
||||||
.queueid = to_msm_pipe(ring->pipe)->queue_id,
|
.queueid = msm_pipe->queue_id,
|
||||||
};
|
};
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int ret;
|
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);
|
assert(to_msm_ringbuffer(ring)->is_growable);
|
||||||
finalize_current_cmd(ring, ring->last_start);
|
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)
|
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->reloc_offset = r->offset;
|
||||||
reloc->or = r->or;
|
reloc->or = r->or;
|
||||||
reloc->shift = r->shift;
|
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;
|
addr = msm_bo->presumed;
|
||||||
if (reloc->shift < 0)
|
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->reloc_offset = r->offset;
|
||||||
reloc_hi->or = r->orhi;
|
reloc_hi->or = r->orhi;
|
||||||
reloc_hi->shift = r->shift - 32;
|
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;
|
addr = msm_bo->presumed >> 32;
|
||||||
if (reloc_hi->shift < 0)
|
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)
|
uint32_t submit_offset, uint32_t size)
|
||||||
{
|
{
|
||||||
struct msm_cmd *cmd = NULL;
|
struct msm_cmd *cmd = NULL;
|
||||||
|
struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target);
|
||||||
uint32_t idx = 0;
|
uint32_t idx = 0;
|
||||||
int added_cmd = FALSE;
|
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)
|
if (idx == cmd_idx)
|
||||||
break;
|
break;
|
||||||
idx++;
|
idx++;
|
||||||
|
@ -540,7 +592,7 @@ static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
|
||||||
|
|
||||||
assert(cmd && (idx == cmd_idx));
|
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
|
/* 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,
|
* 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
|
* 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->size = size;
|
||||||
ring->pipe = pipe; /* needed in ring_cmd_new() */
|
ring->pipe = pipe; /* needed in ring_cmd_new() */
|
||||||
|
|
||||||
ring_cmd_new(ring, size);
|
ring_cmd_new(ring, size, flags);
|
||||||
|
|
||||||
return ring;
|
return ring;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue