Commit 739181c8 authored by Michel Dänzer's avatar Michel Dänzer Committed by Michel Dänzer
Browse files

Add amdgpu_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.
parent 6029794e
......@@ -40,6 +40,7 @@
struct amdgpu_drm_queue_entry {
struct xorg_list list;
uint64_t usec;
uint64_t id;
uintptr_t seq;
void *data;
......@@ -47,38 +48,75 @@ struct amdgpu_drm_queue_entry {
xf86CrtcPtr crtc;
amdgpu_drm_handler_proc handler;
amdgpu_drm_abort_proc abort;
unsigned int frame;
};
static int amdgpu_drm_queue_refcnt;
static struct xorg_list amdgpu_drm_queue;
static struct xorg_list amdgpu_drm_flip_signalled;
static struct xorg_list amdgpu_drm_vblank_signalled;
static uintptr_t amdgpu_drm_queue_seq;
/*
* Handle a DRM event
* Process a DRM event
*/
static void
amdgpu_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, void *user_ptr)
amdgpu_drm_queue_handle_one(struct amdgpu_drm_queue_entry *e)
{
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
amdgpu_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 amdgpu_drm_queue_entry *e, *tmp;
xorg_list_for_each_entry_safe(e, tmp, &amdgpu_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
if (!e->handler) {
e->abort(e->crtc, e->data);
free(e);
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
amdgpu_drm_page_flip_handler(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, void *user_ptr)
{
amdgpu_drm_queue_handler(&amdgpu_drm_flip_signalled, frame, sec, usec,
user_ptr);
}
/*
* Signal a DRM vblank event
*/
static void
amdgpu_drm_vblank_handler(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, void *user_ptr)
{
amdgpu_drm_queue_handler(&amdgpu_drm_vblank_signalled, frame, sec, usec,
user_ptr);
}
/*
* Enqueue a potential drm response; when the associated response
* appears, we've got data to pass to the handler from here
......@@ -177,6 +215,26 @@ amdgpu_drm_abort_id(uint64_t id)
}
}
/*
* drmHandleEvent wrapper
*/
int
amdgpu_drm_handle_event(int fd, drmEventContext *event_context)
{
struct amdgpu_drm_queue_entry *e, *tmp;
int r;
r = drmHandleEvent(fd, event_context);
xorg_list_for_each_entry_safe(e, tmp, &amdgpu_drm_flip_signalled, list)
amdgpu_drm_queue_handle_one(e);
xorg_list_for_each_entry_safe(e, tmp, &amdgpu_drm_vblank_signalled, list)
amdgpu_drm_queue_handle_one(e);
return r;
}
/*
* Wait for pending page flip on given CRTC to complete
*/
......@@ -184,10 +242,14 @@ void amdgpu_drm_wait_pending_flip(xf86CrtcPtr crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
drmmode_ptr drmmode = drmmode_crtc->drmmode;
struct amdgpu_drm_queue_entry *e, *tmp;
xorg_list_for_each_entry_safe(e, tmp, &amdgpu_drm_flip_signalled, list)
amdgpu_drm_queue_handle_one(e);
while (drmmode_crtc->flip_pending &&
drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context) > 0);
while (drmmode_crtc->flip_pending
&& amdgpu_drm_handle_event(pAMDGPUEnt->fd,
&drmmode_crtc->drmmode->event_context) > 0);
}
/*
......@@ -200,13 +262,15 @@ amdgpu_drm_queue_init(ScrnInfoPtr scrn)
drmmode_ptr drmmode = &info->drmmode;
drmmode->event_context.version = 2;
drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler;
drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler;
drmmode->event_context.vblank_handler = amdgpu_drm_vblank_handler;
drmmode->event_context.page_flip_handler = amdgpu_drm_page_flip_handler;
if (amdgpu_drm_queue_refcnt++)
return;
xorg_list_init(&amdgpu_drm_queue);
xorg_list_init(&amdgpu_drm_flip_signalled);
xorg_list_init(&amdgpu_drm_vblank_signalled);
}
/*
......
......@@ -49,6 +49,7 @@ uintptr_t amdgpu_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
void amdgpu_drm_abort_client(ClientPtr client);
void amdgpu_drm_abort_entry(uintptr_t seq);
void amdgpu_drm_abort_id(uint64_t id);
int amdgpu_drm_handle_event(int fd, drmEventContext *event_context);
void amdgpu_drm_wait_pending_flip(xf86CrtcPtr crtc);
void amdgpu_drm_queue_init(ScrnInfoPtr scrn);
void amdgpu_drm_queue_close(ScrnInfoPtr scrn);
......
......@@ -110,7 +110,7 @@ amdgpu_present_flush_drm_events(ScreenPtr screen)
if (r <= 0)
return 0;
return drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context) >= 0;
return amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context) >= 0;
}
/*
......
......@@ -3096,7 +3096,7 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
static void drmmode_notify_fd(int fd, int notify, void *data)
{
drmmode_ptr drmmode = data;
drmHandleEvent(fd, &drmmode->event_context);
amdgpu_drm_handle_event(fd, &drmmode->event_context);
}
#else
static void drm_wakeup_handler(pointer data, int err, pointer p)
......@@ -3106,7 +3106,7 @@ static void drm_wakeup_handler(pointer data, int err, pointer p)
fd_set *read_mask = p;
if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) {
drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context);
amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context);
}
}
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment