summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-11-19 10:03:58 +1000
committerBen Skeggs <bskeggs@redhat.com>2013-11-22 14:50:12 +1000
commitb213d4e79a4633003700d52e179baa61c3a64f71 (patch)
tree2d1890c3022a0065e63e37bbdb633e5ca9984f5b
parent4ff466beee67de449393b4d04f164614f0755e80 (diff)
downloadxorg-driver-xf86-video-nouveau-b213d4e79a4633003700d52e179baa61c3a64f71.tar.gz
kms: implement a more generic drm event handler
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/drmmode_display.c103
-rw-r--r--src/nouveau_dri2.c49
-rw-r--r--src/nv_proto.h7
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);