Index: hw/xfree86/os-support/drm/xf86drm.c =================================================================== RCS file: /cvs/xorg/xserver/xorg/hw/xfree86/os-support/drm/xf86drm.c,v retrieving revision 1.2 diff -u -r1.2 xf86drm.c --- hw/xfree86/os-support/drm/xf86drm.c 10 Feb 2006 22:00:25 -0000 1.2 +++ hw/xfree86/os-support/drm/xf86drm.c 11 Mar 2006 22:01:30 -0000 @@ -528,6 +528,120 @@ return -1; } +/* + * DRM based VBLANK support + * + * We add a new system counter called "VBLANK" if the underlying DRM driver we + * just opened supports vblank. + * + * FIXME: multihead? one counter per head? + */ +#define _SYNC_SERVER +#include +#include +static void *drmVBlankCounter; +static XSyncValue curVBlankCount; +static XSyncValue *nextVBlankCount; + +/* + * Increment the Xsync VBLANK counter and request another signal. + * + * Note that we can't call SyncChangeCounter here to fire the triggers + * since we don't know where the server was interrupted (it could have + * been while updating the trigger list or something). + */ +static void drmVBlankSigHandler(int fd, void *oldctx, void *newctx) +{ + XSyncValue add; + drmVBlank vbl; + int ovf; + + XSyncIntToValue(&add, 1); + XSyncValueAdd(&curVBlankCount, curVBlankCount, add, &ovf); + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_SIGNAL; + vbl.request.sequence = 1; /* next event */ + drmWaitVBlank(fd, &vbl); /* Ask for the signal */ +} + +/* + * Nothing to do here. + */ +static void drmVBlankBlockHandler(void *env, struct timeval **wt, + void *LastSelectMask) +{ + return; +} + +/* + * The XSync architecture is vulnerable to laggy wakeup handling since the + * signal handler can't call SyncChangeCounter by itself (no locking means + * the triggers called by SyncChangeCounter might change from underneath it). + * That means we could get to this point way after the VBLANK actually + * occurred, which probably isn't what the client wanted. + */ +static void drmVBlankWakeupHandler(void *env, int rc, void *LastSelectMask) +{ + /* Fire the triggers if we have a waiter and their time has come */ + if (nextVBlankCount && XSyncValueGreaterOrEqual(curVBlankCount, + *nextVBlankCount)) + SyncChangeCounter(drmVBlankCounter, curVBlankCount); +} + +/* + * Just return the current value of the VBLANK counter. + */ +static void drmVBlankQueryValue(void *pCounter, CARD64 *pValue_return) +{ + *pValue_return = curVBlankCount; +} + +/* + * Setup a notification request. + */ +static void drmVBlankBracketValues(void *pCounter, CARD64 *pbracket_less, + CARD64 *pbracket_greater) +{ + if (!nextVBlankCount && pbracket_greater) + RegisterBlockAndWakeupHandlers(drmVBlankBlockHandler, + drmVBlankWakeupHandler, + NULL); + else if (nextVBlankCount && !pbracket_greater) + RemoveBlockAndWakeupHandlers(drmVBlankBlockHandler, + drmVBlankWakeupHandler, + NULL); + nextVBlankCount = pbracket_greater; +} + +/* + * Setup VBLANK support if possible + * + * Setup the DRM VBLANK SIGIO handler then try requesting a VBLANK interrupt. + * If the driver supports it, create the XSync counter and continue on our + * merry way. + */ +static void SyncInitDrmVBlank(int fd) +{ + XSyncValue start, res; + drmVBlank vbl; + int ret; + + drmInstallSIGIOHandler(fd, drmVBlankSigHandler); + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_SIGNAL; + vbl.request.sequence = 1; /* next event */ + if ((ret = drmWaitVBlank(fd, &vbl))) { + ErrorF("[drm] failed to regsister vblank handler: %s\n", + strerror(-ret)); + drmRemoveSIGIOHandler(fd); + return; + } + + XSyncIntToValue(&start, 0); + XSyncIntToValue(&res, 1); + drmVBlankCounter = SyncCreateSystemCounter("VBLANK", start, res, + XSyncCounterNeverDecreases, + drmVBlankQueryValue, + drmVBlankBracketValues); +} /** * Open the DRM device. @@ -546,6 +660,8 @@ */ int drmOpen(const char *name, const char *busid) { + int fd = -1; + #ifdef XFree86Server if (!drmAvailable() && name != NULL) { /* try to load the kernel */ @@ -557,16 +673,15 @@ } #endif - if (busid) { - int fd; - + if (busid) fd = drmOpenByBusid(busid); - if (fd >= 0) - return fd; - } - if (name) - return drmOpenByName(name); - return -1; + if (fd < 0 && name) + fd = drmOpenByName(name); + if (fd < 0) + return -1; + + SyncInitDrmVBlank(fd); + return fd; }