diff --git a/include/drm/drm.h b/include/drm/drm.h index 1666e91b..e78775d4 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -806,6 +806,13 @@ struct drm_gem_change_handle { * commits. */ #define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 +/** + * DRM_CAP_ATOMIC_HW_DONE_EVENT + * + * If set to 1, the kernel supports &DRM_MODE_ATOMIC_HW_DONE_EVENT for atomic + * commits. + */ +#define DRM_CAP_ATOMIC_HW_DONE_EVENT 0x16 /* DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { @@ -1380,7 +1387,7 @@ extern "C" { * * Event types 0 - 0x7fffffff are generic DRM events, 0x80000000 and * up are chipset specific. Generic DRM events include &DRM_EVENT_VBLANK, - * &DRM_EVENT_FLIP_COMPLETE and &DRM_EVENT_CRTC_SEQUENCE. + * &DRM_EVENT_FLIP_COMPLETE, &DRM_EVENT_CRTC_SEQUENCE and &DRM_EVENT_ATOMIC_HW_DONE. */ struct drm_event { __u32 type; @@ -1413,6 +1420,17 @@ struct drm_event { * The event payload is a struct drm_event_crtc_sequence. */ #define DRM_EVENT_CRTC_SEQUENCE 0x03 +/** + * DRM_EVENT_ATOMIC_HW_DONE - atomic commit HW done event + * + * This event is sent in response to an atomic commit with the + * &DRM_MODE_ATOMIC_HW_DONE_EVENT flag set. + * + * One event is sent per commit. + * + * The event payload is a struct drm_event_atomic_hw_done. + */ +#define DRM_EVENT_ATOMIC_HW_DONE 0x04 struct drm_event_vblank { struct drm_event base; @@ -1423,6 +1441,17 @@ struct drm_event_vblank { __u32 crtc_id; /* 0 on older kernels that do not support this */ }; +struct drm_event_atomic_hw_done { + struct drm_event base; + __u64 user_data; + + /** + * Timestamp corresponding to when programming the commit to HW completed. + */ + __u32 tv_sec; + __u32 tv_usec; +}; + /* Event delivered at sequence. Time stamp marks when the first pixel * of the refresh cycle leaves the display engine for the display */ diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index cbbbfc1d..babb2554 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -1326,6 +1326,15 @@ struct drm_mode_destroy_dumb { */ #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 +/** + * DRM_MODE_ATOMIC_HW_DONE_EVENT + * + * Request that the kernel sends back an atomic commit HW done event (see + * struct drm_event_atomic_hw_done) with the &DRM_EVENT_ATOMIC_HW_DONE type when + * programming the atomic commit to HW completes. + */ +#define DRM_MODE_ATOMIC_HW_DONE_EVENT 0x0800 + /** * DRM_MODE_ATOMIC_FLAGS * @@ -1337,7 +1346,8 @@ struct drm_mode_destroy_dumb { DRM_MODE_PAGE_FLIP_ASYNC |\ DRM_MODE_ATOMIC_TEST_ONLY |\ DRM_MODE_ATOMIC_NONBLOCK |\ - DRM_MODE_ATOMIC_ALLOW_MODESET) + DRM_MODE_ATOMIC_ALLOW_MODESET |\ + DRM_MODE_ATOMIC_HW_DONE_EVENT) struct drm_mode_atomic { __u32 flags; diff --git a/xf86drm.h b/xf86drm.h index b45337a4..291cfca4 100644 --- a/xf86drm.h +++ b/xf86drm.h @@ -770,7 +770,7 @@ extern int drmSetMaster(int fd); extern int drmDropMaster(int fd); extern int drmIsMaster(int fd); -#define DRM_EVENT_CONTEXT_VERSION 4 +#define DRM_EVENT_CONTEXT_VERSION 5 typedef struct _drmEventContext { @@ -801,6 +801,11 @@ typedef struct _drmEventContext { uint64_t sequence, uint64_t ns, uint64_t user_data); + + void (*atomic_hw_done_handler)(int fd, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); } drmEventContext, *drmEventContextPtr; extern int drmHandleEvent(int fd, drmEventContextPtr evctx); diff --git a/xf86drmMode.c b/xf86drmMode.c index a4873a0f..108649ab 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -1036,6 +1036,7 @@ drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx) struct drm_event *e; struct drm_event_vblank *vblank; struct drm_event_crtc_sequence *seq; + struct drm_event_atomic_hw_done *atomic_hw_done; void *user_data; /* The DRM read semantics guarantees that we always get only @@ -1088,6 +1089,16 @@ drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx) seq->time_ns, seq->user_data); break; + case DRM_EVENT_ATOMIC_HW_DONE: + atomic_hw_done = (struct drm_event_atomic_hw_done *) e; + user_data = U642VOID (atomic_hw_done->user_data); + + if (evctx->version >= 5 && evctx->atomic_hw_done_handler) + evctx->atomic_hw_done_handler(fd, + atomic_hw_done->tv_sec, + atomic_hw_done->tv_usec, + user_data); + break; default: break; }