Add radeon_drm_handle_event wrapper for drmHandleEvent

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)
Acked-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Michel Dänzer
2018-08-16 17:44:45 +02:00
committed by Michel Dänzer
parent 93621e408c
commit ba83a866af
4 changed files with 95 additions and 29 deletions

View File

@@ -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;

View File

@@ -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_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);
}
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;
}
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;
while (drmmode_crtc->flip_pending &&
drmHandleEvent(pRADEONEnt->fd, &drmmode->event_context) > 0);
xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_flip_signalled, list)
radeon_drm_queue_handle_one(e);
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);
}
/*

View File

@@ -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);

View File

@@ -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;
}
/*