summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner.de@gmail.com>2014-08-12 11:08:24 +0200
committerBen Skeggs <bskeggs@redhat.com>2014-08-17 07:34:27 +1000
commit16c885ce9c7bebcfa1252a5d500956dd5f551043 (patch)
tree75ca2150f4ffe81246c67ec007c1f3e25b6f5593
parent7eab6806927ea8938b9bd143d1702e87fde2f2cc (diff)
Fix event handling on multi-x-screen configs.
Only register the wakeup handler and event socket once per card fd and server generation, as the fd and device file is shared between all x-screens for a given card during a given server generation. Without this fix, vblank and kms-pageflip completion event processing don't work properly, as the server doesn't kick the wakeup handler for gpu events, and therefore the desktop will freeze, unless the user manually kicks the wakeup handler by moving the mouse or hitting the keyboard. Add proper reference counting and checks to make it so. This fix is derived from a similar and proven fix in the ati ddx for the same problem. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/drmmode_display.c30
-rw-r--r--src/nv_type.h2
2 files changed, 24 insertions, 8 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index dc15221..6d225cb 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1596,6 +1596,7 @@ drmmode_screen_init(ScreenPtr pScreen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
drmmode_ptr drmmode = drmmode_from_scrn(scrn);
+ NVEntPtr pNVEnt = NVEntPriv(scrn);
/* Setup handler for DRM events */
drmmode_event_init(scrn);
@@ -1603,10 +1604,17 @@ drmmode_screen_init(ScreenPtr pScreen)
/* 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);
+ /* Register wakeup handler only once per servergen, so ZaphodHeads work */
+ if (pNVEnt->fd_wakeup_registered != serverGeneration) {
+ /* Register a wakeup handler to get informed on DRM events */
+ AddGeneralSocket(drmmode->fd);
+ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
+ drmmode_wakeup_handler, scrn);
+ pNVEnt->fd_wakeup_registered = serverGeneration;
+ pNVEnt->fd_wakeup_ref = 1;
+ }
+ else
+ pNVEnt->fd_wakeup_ref++;
}
void
@@ -1614,11 +1622,17 @@ drmmode_screen_fini(ScreenPtr pScreen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
drmmode_ptr drmmode = drmmode_from_scrn(scrn);
+ NVEntPtr pNVEnt = NVEntPriv(scrn);
- /* Unregister wakeup handler */
- RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
- drmmode_wakeup_handler, scrn);
- RemoveGeneralSocket(drmmode->fd);
+ /* Unregister wakeup handler after last x-screen for this servergen dies. */
+ if (pNVEnt->fd_wakeup_registered == serverGeneration &&
+ !--pNVEnt->fd_wakeup_ref) {
+
+ /* Unregister wakeup handler */
+ RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
+ drmmode_wakeup_handler, scrn);
+ RemoveGeneralSocket(drmmode->fd);
+ }
/* Tear down udev event handler */
drmmode_uevent_fini(scrn);
diff --git a/src/nv_type.h b/src/nv_type.h
index 3e7c234..c0517c6 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -34,6 +34,8 @@ typedef struct {
unsigned long reinitGeneration;
struct xf86_platform_device *platform_dev;
unsigned int assigned_crtcs;
+ unsigned long fd_wakeup_registered;
+ int fd_wakeup_ref;
} NVEntRec, *NVEntPtr;
NVEntPtr NVEntPriv(ScrnInfoPtr pScrn);