summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--freedreno/freedreno_bo.c68
-rw-r--r--freedreno/freedreno_pipe.c23
-rw-r--r--freedreno/freedreno_priv.h10
-rw-r--r--freedreno/freedreno_ringbuffer.c4
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, &timestamp))
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;
}