diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2018-07-25 13:00:15 +0200 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2018-08-16 17:11:24 +0200 |
commit | 739181c8d3334ff14b5a607895dfdeb29b0d9020 (patch) | |
tree | 5336ab593724bd0cd933debdee087d936cd6339c | |
parent | 6029794e8a35417faf825491a89b85f713c77fc1 (diff) |
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.
-rw-r--r-- | src/amdgpu_drm_queue.c | 94 | ||||
-rw-r--r-- | src/amdgpu_drm_queue.h | 1 | ||||
-rw-r--r-- | src/amdgpu_present.c | 2 | ||||
-rw-r--r-- | src/drmmode_display.c | 4 |
4 files changed, 83 insertions, 18 deletions
diff --git a/src/amdgpu_drm_queue.c b/src/amdgpu_drm_queue.c index 9c01661..f866082 100644 --- a/src/amdgpu_drm_queue.c +++ b/src/amdgpu_drm_queue.c @@ -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,39 +48,76 @@ 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 */ @@ -178,16 +216,40 @@ 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 */ 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); } /* diff --git a/src/amdgpu_drm_queue.h b/src/amdgpu_drm_queue.h index cb6d5ff..48ba9ab 100644 --- a/src/amdgpu_drm_queue.h +++ b/src/amdgpu_drm_queue.h @@ -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); diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c index 4e74bfa..a6676af 100644 --- a/src/amdgpu_present.c +++ b/src/amdgpu_present.c @@ -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; } /* diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 7f521b6..167b300 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -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 |