From b213d4e79a4633003700d52e179baa61c3a64f71 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Nov 2013 10:03:58 +1000 Subject: kms: implement a more generic drm event handler Signed-off-by: Ben Skeggs --- src/drmmode_display.c | 103 ++++++++++++++++++++++++++++++++++++++++++++------ src/nouveau_dri2.c | 49 +++++++++++++----------- src/nv_proto.h | 7 +++- 3 files changed, 122 insertions(+), 37 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index df3e43b..9d0cdec 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -49,6 +49,7 @@ typedef struct { drmModeResPtr mode_res; int cpp; drmEventContext event_context; + struct xorg_list events; #ifdef HAVE_LIBUDEV struct udev_monitor *uevent_monitor; #endif @@ -115,6 +116,92 @@ drmmode_swap(ScrnInfoPtr scrn, uint32_t next, uint32_t *prev) drmmode->fb_id = next; } +struct drmmode_event { + struct xorg_list head; + drmmode_ptr drmmode; + uint64_t name; + void (*func)(void *, uint64_t, uint64_t, uint32_t); +}; + +static void +drmmode_event_handler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + const uint64_t ust = (uint64_t)tv_sec * 1000000 + tv_usec; + struct drmmode_event *e = event_data; + + if (!xorg_list_is_empty(&e->head)) { + xorg_list_del(&e->head); + e->func((void *)(e + 1), e->name, ust, frame); + } + + free(e); +} + +void +drmmode_event_abort(ScrnInfoPtr scrn, uint64_t name, bool pending) +{ + drmmode_ptr drmmode = drmmode_from_scrn(scrn); + struct drmmode_event *e, *t; + + xorg_list_for_each_entry_safe(e, t, &drmmode->events, head) { + if (e->name == name) { + xorg_list_del(&e->head); + if (!pending) + free(e); + break; + } + } +} + +void * +drmmode_event_queue(ScrnInfoPtr scrn, uint64_t name, unsigned size, + void (*func)(void *, uint64_t, uint64_t, uint32_t), + void **event_data) +{ + drmmode_ptr drmmode = drmmode_from_scrn(scrn); + struct drmmode_event *e; + + e = *event_data = calloc(1, sizeof(*e) + size); + if (e) { + e->drmmode = drmmode; + e->name = name; + e->func = func; + xorg_list_add(&e->head, &drmmode->events); + return (void *)(e + 1); + } + + return NULL; +} + +int +drmmode_event_flush(ScrnInfoPtr scrn) +{ + drmmode_ptr drmmode = drmmode_from_scrn(scrn); + return drmHandleEvent(drmmode->fd, &drmmode->event_context); +} + +void +drmmode_event_fini(ScrnInfoPtr scrn) +{ + drmmode_ptr drmmode = drmmode_from_scrn(scrn); + struct drmmode_event *e, *t; + + xorg_list_for_each_entry_safe(e, t, &drmmode->events, head) { + xorg_list_del(&e->head); + } +} + +void +drmmode_event_init(ScrnInfoPtr scrn) +{ + drmmode_ptr drmmode = drmmode_from_scrn(scrn); + drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; + drmmode->event_context.vblank_handler = drmmode_event_handler; + drmmode->event_context.page_flip_handler = drmmode_event_handler; + xorg_list_init(&drmmode->events); +} + static PixmapPtr drmmode_pixmap_wrap(ScreenPtr pScreen, int width, int height, int depth, int bpp, int pitch, struct nouveau_bo *bo, void *data) @@ -1451,17 +1538,9 @@ drmmode_screen_init(ScreenPtr pScreen) drmmode_ptr drmmode = drmmode_from_scrn(scrn); drmmode_uevent_init(scrn); - - /* Plug in a vblank event handler */ - drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; - drmmode->event_context.vblank_handler = nouveau_dri2_vblank_handler; - - /* Plug in a pageflip completion event handler */ - drmmode->event_context.page_flip_handler = drmmode_flip_handler; + drmmode_event_init(scrn); AddGeneralSocket(drmmode->fd); - - /* Register a wakeup handler to get informed on DRM events */ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, scrn); } @@ -1472,10 +1551,10 @@ drmmode_screen_fini(ScreenPtr pScreen) ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); drmmode_ptr drmmode = drmmode_from_scrn(scrn); - drmmode_uevent_fini(scrn); - - /* Register a wakeup handler to get informed on DRM events */ RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, scrn); RemoveGeneralSocket(drmmode->fd); + + drmmode_event_fini(scrn); + drmmode_uevent_fini(scrn); } diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c index 54cacbb..3042af8 100644 --- a/src/nouveau_dri2.c +++ b/src/nouveau_dri2.c @@ -389,12 +389,14 @@ nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, } } -void -drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) +static void +drmmode_flip_handler(void *priv, uint64_t name, uint64_t ust, uint32_t msc) { - drmmode_flipevtcarrier_ptr flipcarrier = event_data; + drmmode_flipevtcarrier_ptr flipcarrier = priv; drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; + const unsigned int tv_sec = ust / 1000000; + const unsigned int tv_usec = ust % 1000000; + const unsigned int frame = msc; /* Is this the event whose info shall be delivered to higher level? */ if (flipcarrier->dispatch_me) { @@ -403,7 +405,6 @@ drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, flipdata->fe_tv_sec = tv_sec; flipdata->fe_tv_usec = tv_usec; } - free(flipcarrier); /* Last crtc completed flip? */ flipdata->flip_count--; @@ -461,13 +462,15 @@ drmmode_page_flip(DrawablePtr draw, PixmapPtr back, for (i = 0; i < config->num_crtc; i++) { int head = drmmode_head(config->crtc[i]); + void *token; if (!config->crtc[i]->enabled) continue; flipdata->flip_count++; - flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); + flipcarrier = drmmode_event_queue(scrn, 0, sizeof(*flipcarrier), + drmmode_flip_handler, &token); if (!flipcarrier) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue: carrier alloc failed.\n"); @@ -483,12 +486,11 @@ drmmode_page_flip(DrawablePtr draw, PixmapPtr back, flipcarrier->flipdata = flipdata; ret = drmModePageFlip(pNv->dev->fd, head, next_fb, - DRM_MODE_PAGE_FLIP_EVENT, flipcarrier); + DRM_MODE_PAGE_FLIP_EVENT, token); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", strerror(errno)); - - free(flipcarrier); + drmmode_event_abort(scrn, 0, false); if (emitted == 0) free(flipdata); goto error_undo; @@ -511,12 +513,13 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, struct nouveau_dri2_vblank_state *s); -void -nouveau_dri2_vblank_handler(int fd, unsigned int frame, - unsigned int tv_sec, unsigned int tv_usec, - void *event_data) +static void +nouveau_dri2_vblank_handler(void *priv, uint64_t name, uint64_t ust, uint32_t msc) { - struct nouveau_dri2_vblank_state *s = event_data; + struct nouveau_dri2_vblank_state *s = priv; + const unsigned int tv_sec = ust / 1000000; + const unsigned int tv_usec = ust % 1000000; + const unsigned int frame = msc; DrawablePtr draw; int ret; @@ -557,34 +560,34 @@ nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc, int crtcs = nv_window_belongs_to_crtc(scrn, draw->x, draw->y, draw->width, draw->height); drmVBlank vbl; - void *data; + struct nouveau_dri2_vblank_state *data; + void *token; int ret; if (type & DRM_VBLANK_EVENT) { - data = malloc(sizeof(*s)); + data = drmmode_event_queue(scrn, 0, sizeof(*data), + nouveau_dri2_vblank_handler, &token); if (!data) return -ENOMEM; memcpy(data, s, sizeof(*s)); } else { - data = s; + data = token = s; } vbl.request.type = type | (crtcs == 2 ? DRM_VBLANK_SECONDARY : 0); vbl.request.sequence = msc; - vbl.request.signal = (unsigned long)data; + vbl.request.signal = (unsigned long)token; ret = drmWaitVBlank(pNv->dev->fd, &vbl); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Wait for VBlank failed: %s\n", strerror(errno)); + drmmode_event_abort(scrn, 0, false); return ret; } - if (type & DRM_VBLANK_EVENT) { - s = data; - s->frame = vbl.reply.sequence + 1; - } - + if (type & DRM_VBLANK_EVENT) + data->frame = vbl.reply.sequence + 1; if (pmsc) *pmsc = vbl.reply.sequence; if (pust) diff --git a/src/nv_proto.h b/src/nv_proto.h index 09f7ede..937cedd 100644 --- a/src/nv_proto.h +++ b/src/nv_proto.h @@ -13,8 +13,11 @@ void drmmode_screen_fini(ScreenPtr pScreen); int drmmode_head(xf86CrtcPtr crtc); void drmmode_swap(ScrnInfoPtr, uint32_t, uint32_t *); -void drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data); -void nouveau_dri2_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data); +void *drmmode_event_queue(ScrnInfoPtr, uint64_t name, unsigned size, + void (*)(void *, uint64_t, uint64_t, uint32_t), + void **token); +void drmmode_event_abort(ScrnInfoPtr, uint64_t name, bool pending); +int drmmode_event_flush(ScrnInfoPtr); /* in nv_accel_common.c */ Bool NVAccelCommonInit(ScrnInfoPtr pScrn); -- cgit v1.2.1