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)
}
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;
+}
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;
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))
* 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 {
* 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]))
};
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 */
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;
}