From 0d94f32fce2759c4b0f4d22b99f3ced09c2aa5a0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 20 Jun 2014 09:47:39 +1000 Subject: kms: implement a more generic event mechanism Present wants to use this too. Signed-off-by: Ben Skeggs --- src/drmmode_display.c | 120 +++++++++++++++++++++++++++++++++++++++++++++----- src/nouveau_dri2.c | 71 +++++++++++++++++++---------- src/nv_proto.h | 12 ++--- 3 files changed, 161 insertions(+), 42 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index a46aad5..58b5e07 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -126,6 +126,102 @@ 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 struct xorg_list +drmmode_events = { + .next = &drmmode_events, + .prev = &drmmode_events, +}; + +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; + + xorg_list_for_each_entry(e, &drmmode_events, head) { + if (e == event_data) { + xorg_list_del(&e->head); + e->func((void *)(e + 1), e->name, ust, frame); + free(e); + break; + } + } +} + +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->drmmode == drmmode && 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_append(&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) { + if (e->drmmode == drmmode) { + xorg_list_del(&e->head); + free(e); + } + } +} + +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; +} + static PixmapPtr drmmode_pixmap_wrap(ScreenPtr pScreen, int width, int height, int depth, int bpp, int pitch, struct nouveau_bo *bo, void *data) @@ -1464,18 +1560,14 @@ drmmode_screen_init(ScreenPtr pScreen) ScrnInfoPtr scrn = xf86ScreenToScrn(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; + /* Setup handler for DRM events */ + drmmode_event_init(scrn); - /* Plug in a pageflip completion event handler */ - drmmode->event_context.page_flip_handler = nouveau_dri2_flip_handler; - - AddGeneralSocket(drmmode->fd); + /* Setup handler for udevevents */ + drmmode_uevent_init(scrn); /* Register a wakeup handler to get informed on DRM events */ + AddGeneralSocket(drmmode->fd); RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, scrn); } @@ -1486,10 +1578,14 @@ 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 */ + /* Unregister wakeup handler */ RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, scrn); RemoveGeneralSocket(drmmode->fd); + + /* Tear down udev event handler */ + drmmode_uevent_fini(scrn); + + /* Tear down DRM event handler */ + drmmode_event_fini(scrn); } diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c index 8a0cddd..5848966 100644 --- a/src/nouveau_dri2.c +++ b/src/nouveau_dri2.c @@ -230,6 +230,12 @@ struct nouveau_dri2_vblank_state { unsigned int frame; }; +struct dri2_vblank { + struct nouveau_dri2_vblank_state *s; +}; + +static uint64_t dri2_sequence; + static Bool update_front(DrawablePtr draw, DRI2BufferPtr front) { @@ -328,9 +334,8 @@ typedef struct { unsigned old_fb_id; int flip_count; void *event_data; - unsigned int fe_frame; - unsigned int fe_tv_sec; - unsigned int fe_tv_usec; + unsigned int fe_msc; + unsigned int fe_ust; } dri2_flipdata_rec, *dri2_flipdata_ptr; typedef struct { @@ -338,7 +343,7 @@ typedef struct { Bool dispatch_me; } dri2_flipevtcarrier_rec, *dri2_flipevtcarrier_ptr; -void +static void nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data) { @@ -393,21 +398,18 @@ nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, free(flip); } -void -nouveau_dri2_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) +static void +nouveau_dri2_flip_handler(void *priv, uint64_t name, uint64_t ust, uint32_t msc) { - dri2_flipevtcarrier_ptr flipcarrier = event_data; + dri2_flipevtcarrier_ptr flipcarrier = priv; dri2_flipdata_ptr flipdata = flipcarrier->flipdata; /* Is this the event whose info shall be delivered to higher level? */ if (flipcarrier->dispatch_me) { /* Yes: Cache msc, ust for later delivery. */ - flipdata->fe_frame = frame; - flipdata->fe_tv_sec = tv_sec; - flipdata->fe_tv_usec = tv_usec; + flipdata->fe_msc = msc; + flipdata->fe_ust = ust; } - free(flipcarrier); /* Last crtc completed flip? */ flipdata->flip_count--; @@ -423,8 +425,10 @@ nouveau_dri2_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, } /* Deliver cached msc, ust from reference crtc to flip event handler */ - nouveau_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec, - flipdata->fe_tv_usec, flipdata->event_data); + nouveau_dri2_flip_event_handler(flipdata->fe_msc, + flipdata->fe_ust / 1000000, + flipdata->fe_ust % 1000000, + flipdata->event_data); free(flipdata); } @@ -463,13 +467,17 @@ dri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, 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(dri2_flipevtcarrier_rec)); + flipcarrier = drmmode_event_queue(scrn, ++dri2_sequence, + sizeof(*flipcarrier), + nouveau_dri2_flip_handler, + &token); if (!flipcarrier) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue: carrier alloc failed.\n"); @@ -485,12 +493,11 @@ dri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, 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, dri2_sequence--, false); if (emitted == 0) free(flipdata); goto error_undo; @@ -513,12 +520,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 frame) { - struct nouveau_dri2_vblank_state *s = event_data; + struct dri2_vblank *event = priv; + struct nouveau_dri2_vblank_state *s = event->s; + uint32_t tv_sec = ust / 1000000; + uint32_t tv_usec = ust % 1000000; DrawablePtr draw; int ret; @@ -561,16 +569,31 @@ 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; + struct dri2_vblank *event = NULL; + void *token = NULL; int ret; + if (type & DRM_VBLANK_EVENT) { + event = drmmode_event_queue(scrn, ++dri2_sequence, + sizeof(*event), + nouveau_dri2_vblank_handler, + &token); + if (!event) + return -ENOMEM; + + event->s = data; + } + 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)); + if (event) + drmmode_event_abort(scrn, dri2_sequence--, false); return ret; } diff --git a/src/nv_proto.h b/src/nv_proto.h index 134fba4..c076461 100644 --- a/src/nv_proto.h +++ b/src/nv_proto.h @@ -15,6 +15,12 @@ void drmmode_screen_fini(ScreenPtr pScreen); int drmmode_head(xf86CrtcPtr crtc); void drmmode_swap(ScrnInfoPtr, uint32_t, uint32_t *); +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); void NVAccelCommonFini(ScrnInfoPtr pScrn); @@ -27,12 +33,6 @@ Bool nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, struct nouveau_bo **bo); /* in nouveau_dri2.c */ -void nouveau_dri2_vblank_handler(int fd, unsigned int frame, - unsigned int tv_sec, unsigned int tv_usec, - void *event_data); -void nouveau_dri2_flip_handler(int fd, unsigned int frame, - unsigned int tv_sec, unsigned int tv_usec, - void *event_data); Bool nouveau_dri2_init(ScreenPtr pScreen); void nouveau_dri2_fini(ScreenPtr pScreen); -- cgit v1.2.3