summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-06-20 09:47:39 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-06-20 14:28:39 +1000
commit0d94f32fce2759c4b0f4d22b99f3ced09c2aa5a0 (patch)
tree23835bb04108f0eb8c2b713545b0a0ab724dfd90
parent97feb3b2104287eb385ffba8329f304e2808d808 (diff)
kms: implement a more generic event mechanism
Present wants to use this too. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/drmmode_display.c120
-rw-r--r--src/nouveau_dri2.c71
-rw-r--r--src/nv_proto.h12
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);