diff options
-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; } |