[PATCH xf86-video-ati 3/5] Add radeon_drm_handle_event wrapper for drmHandleEvent

Michel Dänzer michel at daenzer.net
Thu Aug 16 16:19:40 UTC 2018


From: Michel Dänzer <michel.daenzer at amd.com>

Instead of processing DRM events directly from drmHandleEvent's
callbacks, there are three phases:

1. drmHandleEvent is called, and signalled events are re-queued to
   _signalled lists from its callbacks.
2. Signalled page flip completion events are processed.
3. Signalled vblank events are processed.

This should make sure that we never call drmHandleEvent from one of its
callbacks, which would usually result in blocking forever.

(Ported from amdgpu commit 739181c8d3334ff14b5a607895dfdeb29b0d9020)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/drmmode_display.c  |  13 ++---
 src/radeon_drm_queue.c | 110 ++++++++++++++++++++++++++++++++---------
 src/radeon_drm_queue.h |   1 +
 src/radeon_present.c   |   2 +-
 4 files changed, 96 insertions(+), 30 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 59fe9b7fc..c022b3e4f 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -2587,9 +2587,8 @@ static void
 drm_wakeup_handler(pointer data, int err, pointer p)
 #endif
 {
-	ScrnInfoPtr scrn = data;
-	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
-	RADEONInfoPtr info = RADEONPTR(scrn);
+	drmmode_ptr drmmode = data;
+	RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn);
 	
 #if !HAVE_NOTIFY_FD
 	fd_set *read_mask = p;
@@ -2597,7 +2596,7 @@ drm_wakeup_handler(pointer data, int err, pointer p)
 	if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask))
 #endif
 	{
-		drmHandleEvent(pRADEONEnt->fd, &info->drmmode.event_context);
+		radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context);
 	}
 }
 
@@ -2747,11 +2746,13 @@ void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	info->drmmode_inited = TRUE;
 	if (pRADEONEnt->fd_wakeup_registered != serverGeneration) {
 #if HAVE_NOTIFY_FD
-		SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ, pScrn);
+		SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ,
+			    &info->drmmode);
 #else
 		AddGeneralSocket(pRADEONEnt->fd);
 		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
-				drm_wakeup_handler, pScrn);
+					       drm_wakeup_handler,
+					       &info->drmmode);
 #endif
 		pRADEONEnt->fd_wakeup_registered = serverGeneration;
 		pRADEONEnt->fd_wakeup_ref = 1;
diff --git a/src/radeon_drm_queue.c b/src/radeon_drm_queue.c
index 69474be24..3d2f4d157 100644
--- a/src/radeon_drm_queue.c
+++ b/src/radeon_drm_queue.c
@@ -40,6 +40,7 @@
 
 struct radeon_drm_queue_entry {
     struct xorg_list list;
+    uint64_t usec;
     uint64_t id;
     uintptr_t seq;
     void *data;
@@ -47,36 +48,73 @@ struct radeon_drm_queue_entry {
     xf86CrtcPtr crtc;
     radeon_drm_handler_proc handler;
     radeon_drm_abort_proc abort;
+    unsigned int frame;
 };
 
 static int radeon_drm_queue_refcnt;
 static struct xorg_list radeon_drm_queue;
+static struct xorg_list radeon_drm_flip_signalled;
+static struct xorg_list radeon_drm_vblank_signalled;
 static uintptr_t radeon_drm_queue_seq;
 
 
 /*
- * Handle a DRM event
+ * Process a DRM event
  */
 static void
-radeon_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
-			 unsigned int usec, void *user_ptr)
+radeon_drm_queue_handle_one(struct radeon_drm_queue_entry *e)
 {
-	uintptr_t seq = (uintptr_t)user_ptr;
-	struct radeon_drm_queue_entry *e, *tmp;
-
-	xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) {
-		if (e->seq == seq) {
-			xorg_list_del(&e->list);
-			if (e->handler)
-				e->handler(e->crtc, frame,
-					   (uint64_t)sec * 1000000 + usec,
-					   e->data);
-			else
-				e->abort(e->crtc, e->data);
-			free(e);
-			break;
-		}
+    xorg_list_del(&e->list);
+    if (e->handler) {
+	e->handler(e->crtc, e->frame, e->usec, e->data);
+    } else
+	e->abort(e->crtc, e->data);
+    free(e);
+}
+
+static void
+radeon_drm_queue_handler(struct xorg_list *signalled, unsigned int frame,
+			 unsigned int sec, unsigned int usec, void *user_ptr)
+{
+    uintptr_t seq = (uintptr_t)user_ptr;
+    struct radeon_drm_queue_entry *e, *tmp;
+
+    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) {
+	if (e->seq == seq) {
+	    if (!e->handler) {
+		e->abort(e->crtc, e->data);
+		break;
+	    }
+
+	    xorg_list_del(&e->list);
+	    e->usec = (uint64_t)sec * 1000000 + usec;
+	    e->frame = frame;
+	    xorg_list_append(&e->list, signalled);
+	    break;
 	}
+    }
+}
+
+/*
+ * Signal a DRM page flip event
+ */
+static void
+radeon_drm_page_flip_handler(int fd, unsigned int frame, unsigned int sec,
+			     unsigned int usec, void *user_ptr)
+{
+    radeon_drm_queue_handler(&radeon_drm_flip_signalled, frame, sec, usec,
+			     user_ptr);
+}
+
+/*
+ * Signal a DRM vblank event
+ */
+static void
+radeon_drm_vblank_handler(int fd, unsigned int frame, unsigned int sec,
+			  unsigned int usec, void *user_ptr)
+{
+    radeon_drm_queue_handler(&radeon_drm_vblank_signalled, frame, sec, usec,
+			     user_ptr);
 }
 
 /*
@@ -177,6 +215,26 @@ radeon_drm_abort_id(uint64_t id)
     }
 }
 
+/*
+ * drmHandleEvent wrapper
+ */
+int
+radeon_drm_handle_event(int fd, drmEventContext *event_context)
+{
+    struct radeon_drm_queue_entry *e, *tmp;
+    int r;
+
+    r = drmHandleEvent(fd, event_context);
+
+    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_flip_signalled, list)
+	radeon_drm_queue_handle_one(e);
+
+    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_vblank_signalled, list)
+	radeon_drm_queue_handle_one(e);
+
+    return r;
+}
+
 /*
  * Wait for pending page flip on given CRTC to complete
  */
@@ -184,10 +242,14 @@ void radeon_drm_wait_pending_flip(xf86CrtcPtr crtc)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
-    drmmode_ptr drmmode = drmmode_crtc->drmmode;
+    struct radeon_drm_queue_entry *e, *tmp;
+
+    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_flip_signalled, list)
+	radeon_drm_queue_handle_one(e);
 
-    while (drmmode_crtc->flip_pending &&
-	   drmHandleEvent(pRADEONEnt->fd, &drmmode->event_context) > 0);
+    while (drmmode_crtc->flip_pending
+	   && radeon_drm_handle_event(pRADEONEnt->fd,
+					  &drmmode_crtc->drmmode->event_context) > 0);
 }
 
 /*
@@ -200,13 +262,15 @@ radeon_drm_queue_init(ScrnInfoPtr scrn)
     drmmode_ptr drmmode = &info->drmmode;
 
     drmmode->event_context.version = 2;
-    drmmode->event_context.vblank_handler = radeon_drm_queue_handler;
-    drmmode->event_context.page_flip_handler = radeon_drm_queue_handler;
+    drmmode->event_context.vblank_handler = radeon_drm_vblank_handler;
+    drmmode->event_context.page_flip_handler = radeon_drm_page_flip_handler;
 
     if (radeon_drm_queue_refcnt++)
 	return;
 
     xorg_list_init(&radeon_drm_queue);
+    xorg_list_init(&radeon_drm_flip_signalled);
+    xorg_list_init(&radeon_drm_vblank_signalled);
 }
 
 /*
diff --git a/src/radeon_drm_queue.h b/src/radeon_drm_queue.h
index 96f88bd35..593433613 100644
--- a/src/radeon_drm_queue.h
+++ b/src/radeon_drm_queue.h
@@ -47,6 +47,7 @@ uintptr_t radeon_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
 void radeon_drm_abort_client(ClientPtr client);
 void radeon_drm_abort_entry(uintptr_t seq);
 void radeon_drm_abort_id(uint64_t id);
+int radeon_drm_handle_event(int fd, drmEventContext *event_context);
 void radeon_drm_wait_pending_flip(xf86CrtcPtr crtc);
 void radeon_drm_queue_init(ScrnInfoPtr scrn);
 void radeon_drm_queue_close(ScrnInfoPtr scrn);
diff --git a/src/radeon_present.c b/src/radeon_present.c
index 2982d7286..ffc14a0e8 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -110,7 +110,7 @@ radeon_present_flush_drm_events(ScreenPtr screen)
     if (r <= 0)
 	return 0;
 
-    return drmHandleEvent(pRADEONEnt->fd, &drmmode->event_context) >= 0;
+    return radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context) >= 0;
 }
 
 /*
-- 
2.18.0



More information about the amd-gfx mailing list