diff options
author | Rob Clark <robclark@freedesktop.org> | 2013-04-25 16:36:15 -0400 |
---|---|---|
committer | Rob Clark <robclark@freedesktop.org> | 2013-04-25 17:33:59 -0400 |
commit | b3a3a77823ada2eb37233678b5a49efaec9b75cb (patch) | |
tree | f7ca28117adf931551667fc4b020922494408987 | |
parent | ec3c257eb6958da493aee6f010f51a07d7ba4160 (diff) |
freedreno: add synchronization between mesa and ddx
Super-cheezy way to synchronization between mesa and ddx.. the
SET_ACTIVE ioctl gives us a way to stash a 32b # w/ a GEM bo, and
GET_BUFINFO gives us a way to retrieve it. We use this to stash
the timestamp of the last ISSUEIBCMDS on the buffer.
To avoid an obscene amount of syscalls, we:
1) Only set the timestamp for buffers w/ an flink name, ie.
only buffers shared across processes. This is enough to
catch the DRI2 buffers.
2) Only set the timestamp for buffers submitted to the 3d ring
and only check the timestamps on buffers submitted to the
2d ring. This should be enough to handle synchronizing of
presentation blit. We could do synchronization in the other
direction too, but that would be problematic if we are using
the 3d ring from DDX, since client side wouldn't know this.
The waiting on timestamp happens before flush, and setting of
timestamp happens after flush. It is transparent to the user
of libdrm_freedreno as all the tracking of buffers happens via
_emit_reloc()..
Signed-off-by: Rob Clark <robclark@freedesktop.org>
-rw-r--r-- | freedreno/freedreno_bo.c | 68 | ||||
-rw-r--r-- | freedreno/freedreno_pipe.c | 23 | ||||
-rw-r--r-- | freedreno/freedreno_priv.h | 10 | ||||
-rw-r--r-- | freedreno/freedreno_ringbuffer.c | 4 |
4 files changed, 101 insertions, 4 deletions
diff --git a/freedreno/freedreno_bo.c b/freedreno/freedreno_bo.c index 4f566e10..be386b47 100644 --- a/freedreno/freedreno_bo.c +++ b/freedreno/freedreno_bo.c @@ -165,12 +165,17 @@ struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name) struct drm_gem_open req = { .name = name, }; + struct fd_bo *bo; if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { return NULL; } - return bo_from_handle(dev, req.size, req.handle); + bo = bo_from_handle(dev, req.size, req.handle); + if (bo) + bo->name = name; + + return bo; } struct fd_bo * fd_bo_ref(struct fd_bo *bo) @@ -272,3 +277,64 @@ uint32_t fd_bo_gpuaddr(struct fd_bo *bo, uint32_t offset) } return bo->gpuaddr + offset; } + +/* + * Super-cheezy way to synchronization between mesa and ddx.. the + * SET_ACTIVE ioctl gives us a way to stash a 32b # w/ a GEM bo, and + * GET_BUFINFO gives us a way to retrieve it. We use this to stash + * the timestamp of the last ISSUEIBCMDS on the buffer. + * + * To avoid an obscene amount of syscalls, we: + * 1) Only set the timestamp for buffers w/ an flink name, ie. + * only buffers shared across processes. This is enough to + * catch the DRI2 buffers. + * 2) Only set the timestamp for buffers submitted to the 3d ring + * and only check the timestamps on buffers submitted to the + * 2d ring. This should be enough to handle synchronizing of + * presentation blit. We could do synchronization in the other + * direction too, but that would be problematic if we are using + * the 3d ring from DDX, since client side wouldn't know this. + * + * The waiting on timestamp happens before flush, and setting of + * timestamp happens after flush. It is transparent to the user + * of libdrm_freedreno as all the tracking of buffers happens via + * _emit_reloc().. + */ + +void fb_bo_set_timestamp(struct fd_bo *bo, uint32_t timestamp) +{ + if (bo->name) { + struct drm_kgsl_gem_active req = { + .handle = bo->handle, + .active = timestamp, + }; + int ret; + + ret = drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_SET_ACTIVE, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("set active failed: %s", strerror(errno)); + } + } +} + +uint32_t fd_bo_get_timestamp(struct fd_bo *bo) +{ + uint32_t timestamp = 0; + if (bo->name) { + struct drm_kgsl_gem_bufinfo req = { + .handle = bo->handle, + }; + int ret; + + ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("get bufinfo failed: %s", strerror(errno)); + return 0; + } + + timestamp = req.active; + } + return timestamp; +} diff --git a/freedreno/freedreno_pipe.c b/freedreno/freedreno_pipe.c index 1698c466..9f9f1c6e 100644 --- a/freedreno/freedreno_pipe.c +++ b/freedreno/freedreno_pipe.c @@ -199,8 +199,26 @@ void fd_pipe_add_submit(struct fd_pipe *pipe, struct fd_bo *bo) list_addtail(list, &pipe->submit_list); } +/* prepare buffers on submit list before flush: */ +void fd_pipe_pre_submit(struct fd_pipe *pipe) +{ + struct fd_bo *bo; + + if (pipe->id == FD_PIPE_3D) + return; + + if (!pipe->p3d) + pipe->p3d = fd_pipe_new(pipe->dev, FD_PIPE_3D); + + LIST_FOR_EACH_ENTRY(bo, &pipe->submit_list, list[pipe->id]) { + uint32_t timestamp = fd_bo_get_timestamp(bo); + if (timestamp) + fd_pipe_wait(pipe->p3d, timestamp); + } +} + /* process buffers on submit list after flush: */ -void fd_pipe_process_submit(struct fd_pipe *pipe, uint32_t timestamp) +void fd_pipe_post_submit(struct fd_pipe *pipe, uint32_t timestamp) { struct fd_bo *bo, *tmp; @@ -209,6 +227,9 @@ void fd_pipe_process_submit(struct fd_pipe *pipe, uint32_t timestamp) list_del(list); bo->timestamp[pipe->id] = timestamp; list_addtail(list, &pipe->pending_list); + + if (pipe->id == FD_PIPE_3D) + fb_bo_set_timestamp(bo, timestamp); } if (!fd_pipe_timestamp(pipe, ×tamp)) diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h index aa71b564..0edca1d9 100644 --- a/freedreno/freedreno_priv.h +++ b/freedreno/freedreno_priv.h @@ -70,10 +70,16 @@ struct fd_pipe { * not passed yet (so still ref'd in active cmdstream) */ struct list_head pending_list; + + /* if we are the 2d pipe, and want to wait on a timestamp + * from 3d, we need to also internally open the 3d pipe: + */ + struct fd_pipe *p3d; }; void fd_pipe_add_submit(struct fd_pipe *pipe, struct fd_bo *bo); -void fd_pipe_process_submit(struct fd_pipe *pipe, uint32_t timestamp); +void fd_pipe_pre_submit(struct fd_pipe *pipe); +void fd_pipe_post_submit(struct fd_pipe *pipe, uint32_t timestamp); void fd_pipe_process_pending(struct fd_pipe *pipe, uint32_t timestamp); struct fd_bo { @@ -95,6 +101,8 @@ struct fd_bo { * a proper kernel driver */ uint32_t fd_bo_gpuaddr(struct fd_bo *bo, uint32_t offset); +void fb_bo_set_timestamp(struct fd_bo *bo, uint32_t timestamp); +uint32_t fd_bo_get_timestamp(struct fd_bo *bo); #define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1)) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c index f1879964..d20a7f55 100644 --- a/freedreno/freedreno_ringbuffer.c +++ b/freedreno/freedreno_ringbuffer.c @@ -159,6 +159,8 @@ static int flush_impl(struct fd_ringbuffer *ring, uint32_t *last_start) }; int ret; + fd_pipe_pre_submit(ring->pipe); + /* z180_cmdstream_issueibcmds() is made of fail: */ if (ring->pipe->id == FD_PIPE_2D) { /* fix up size field in last cmd packet */ @@ -180,7 +182,7 @@ static int flush_impl(struct fd_ringbuffer *ring, uint32_t *last_start) ring->last_timestamp = req.timestamp; ring->last_start = ring->cur; - fd_pipe_process_submit(ring->pipe, req.timestamp); + fd_pipe_post_submit(ring->pipe, req.timestamp); return ret; } |