lib/XvMC/Imake
authorThomas Hellstrom <unichrome@shipmail.org>
Sat, 13 Nov 2004 11:09:23 +0000 (11:09 +0000)
committerThomas Hellstrom <unichrome@shipmail.org>
Sat, 13 Nov 2004 11:09:23 +0000 (11:09 +0000)
Added support for automatic loading of the correct hardware XvMC driver.
    This involves a protocol extension of the XvMC protocol. The XvMC
    revision number was bumped.

include/X11/extensions/XvMClib.h
src/XvMC.c
src/XvMCWrapper.c

index bc8d7cc..b97ae22 100644 (file)
@@ -1,4 +1,4 @@
-/* $XdotOrg: xc/include/extensions/XvMClib.h,v 1.7 2003/12/18 05:48:06 dawes Exp $ */
+/* $XdotOrg: xc/include/extensions/XvMClib.h,v 1.2 2004/04/23 18:43:06 eich Exp $ */
 /* $XFree86: xc/include/extensions/XvMClib.h,v 1.6 2001/11/14 21:54:37 mvojkovi Exp $ */
 
 #ifndef _XVMCLIB_H_
@@ -13,6 +13,12 @@ _XFUNCPROTOBEGIN
 Bool XvMCQueryExtension (Display *display, int *eventBase, int *errBase);
 Status XvMCQueryVersion (Display *display, int *major_versionp,
                         int *minor_versionp);
+Status XvMCGetDRInfo(Display *dpy, XvPortID port,
+                    char **name, char **busID, 
+                    int *major, int *minor, 
+                    int *patchLevel,
+                    int *isLocal);
+
 
 XvMCSurfaceInfo * XvMCListSurfaceTypes(Display *dpy, XvPortID port, int *num);
 
index f63e278..e022ad9 100644 (file)
@@ -4,6 +4,12 @@
 
 #include <stdio.h>
 #include "XvMClibint.h"
+#ifdef HAS_SHM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+#include <unistd.h>
+#include <sys/time.h>
 #include <X11/extensions/Xext.h>
 #include <X11/extensions/extutil.h>
 
@@ -465,3 +471,124 @@ Status _xvmc_destroy_subpicture(
     return Success;
 }
 
+Status XvMCGetDRInfo(Display *dpy, XvPortID port,
+                    char **name, char **busID, 
+                    int *major, int *minor, 
+                    int *patchLevel,
+                    int *isLocal)
+{
+    XExtDisplayInfo *info = xvmc_find_display(dpy);
+    xvmcGetDRInfoReply rep;
+    xvmcGetDRInfoReq  *req;
+    char *tmpBuf = NULL;
+    CARD32 magic;
+
+#ifdef HAS_SHM
+    volatile CARD32 *shMem;
+    struct timezone here;
+    struct timeval now;
+    here.tz_minuteswest = 0;
+    here.tz_dsttime = 0;
+#endif
+
+    XvMCCheckExtension (dpy, info, BadImplementation);
+
+    LockDisplay (dpy);
+    XvMCGetReq (GetDRInfo, req);
+
+    req->port = port;
+    magic = 0;
+    req->magic = 0;
+#ifdef HAS_SHM 
+    req->shmKey = shmget(IPC_PRIVATE, getpagesize(), IPC_CREAT | 0600);
+
+    /*
+     * We fill a shared memory page with a repetitive pattern. If the
+     * X server can read this pattern, we probably have a local connection.
+     * Note that we can trigger the remote X server to read any shared
+     * page on the remote machine, so we shouldn't be able to guess and verify
+     * any complicated data on those pages. Thats the explanation of this
+     * otherwise stupid-looking pattern algorithm.
+     */
+   
+    if (req->shmKey >= 0) {
+       shMem = (CARD32 *) shmat(req->shmKey, 0, 0);
+       shmctl( req->shmKey, IPC_RMID, 0);
+       if ( shMem ) { 
+
+           register volatile CARD32 *shMemC = shMem;
+           register int i;
+
+           gettimeofday( &now, &here);
+           magic = now.tv_usec & 0x000FFFFF;
+           req->magic = magic;
+           i = getpagesize() / sizeof(CARD32);
+           while(i--) {
+               *shMemC++ = magic; 
+               magic = ~magic;
+           }
+       } else {
+           req->shmKey = -1;
+       }
+    }
+#else
+    req->shmKey = 0;
+#endif
+    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
+        UnlockDisplay (dpy);
+        SyncHandle ();
+#ifdef HAS_SHM
+       if ( req->shmKey >= 0) {
+           shmdt( (const void *) shMem );
+       }            
+#endif
+        return -1;
+    }
+#ifdef HAS_SHM
+    shmdt( (const void *) shMem );
+#endif
+
+    if (rep.length > 0) {
+
+        int realSize = rep.length << 2;
+
+       tmpBuf = (char *) Xmalloc(realSize);
+       if (tmpBuf) {
+           *name = (char *) Xmalloc(rep.nameLen);
+           if (*name) {
+               *busID = (char *) Xmalloc(rep.busIDLen);
+               if (! *busID) {
+                   XFree(*name);
+                   XFree(tmpBuf);
+               }
+           } else {
+               XFree(tmpBuf);
+           }       
+       }
+
+       if (*name && *busID && tmpBuf) {
+
+           _XRead(dpy, tmpBuf, realSize);
+           strncpy(*name,tmpBuf,rep.nameLen);
+           strncpy(*busID,tmpBuf+rep.nameLen,rep.busIDLen);
+           XFree(tmpBuf);
+
+       } else {
+
+           _XEatData(dpy, realSize);
+           UnlockDisplay (dpy);
+           SyncHandle ();
+           return -1;
+
+       }
+    }
+
+    UnlockDisplay (dpy);
+    SyncHandle ();
+    *major = rep.major;
+    *minor = rep.minor;
+    *patchLevel = rep.patchLevel;
+    *isLocal = (req->shmKey > 0) ? rep.isLocal : 1;
+    return (rep.length > 0) ? Success : BadImplementation;
+}
+
index 77f8df9..86e7fa3 100644 (file)
@@ -50,6 +50,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdlib.h>
 
 
 typedef Bool (*XvMCQueryExtensionP) (Display *, int *, int *);
@@ -105,7 +106,8 @@ typedef Status (*XvMCBeginSurfaceP) (Display *,XvMCContext *,XvMCSurface *,
 typedef Status (*XvMCLoadQMatrixP) (Display *, XvMCContext *,const XvMCQMatrix *);
 typedef Status (*XvMCPutSliceP)(Display *,XvMCContext *, char *,int);
 typedef Status (*XvMCPutSlice2P)(Display *,XvMCContext *, char *,int, unsigned);
-typedef char * (*XvMCDRIGetClientDriverNameP)(Display *, XvPortID);
+typedef Status (*XvMCGetDRInfoP)(Display *, XvPortID, char **, char **, int *, int *, 
+                                 int *, int *);
 
 
 typedef struct {
@@ -150,12 +152,11 @@ typedef struct {
     XvMCPutSliceP   XvMCPutSlice;
     XvMCPutSlice2P   XvMCPutSlice2;
 
-
     /*
      * Driver name function.
      */
 
-    XvMCDRIGetClientDriverNameP XvMCDRIGetClientDriverName;
+    XvMCGetDRInfoP XvMCGetDRInfo;
 
     int preInitialised;
     int initialised;
@@ -192,10 +193,38 @@ static void *handle2;
     base.pointer = (pointer##P) dlsym((handle),#pointer);      \
     if (dlerror() != NULL) {                                   \
        base.pointer = (pointer##P) dlsym((handle2),#pointer);  \
-       if (dlerror() != NULL) return;                  \
+       if (dlerror() != NULL) return;                          \
     }                                                  
 
 
+/*
+ * Try to dlopen a shared library, versionless first.
+ */
+
+
+static void  *dlopenversion(const char *lib, const char *version, int flag) 
+{
+  void *ret;
+  int curLen,verLen;
+  char *curName;
+  const char *tail;
+
+  
+  curLen = strlen(lib) + (verLen = strlen(version)) + 1;
+  curName = (char *) malloc(curLen * sizeof(char));
+  strncpy( curName, lib, curLen);
+  if (verLen > 1) {
+    if (NULL != (tail = strstr(version+1,"."))) {
+      strncat( curName, version, tail - version);
+    } else {
+      strncat( curName, version, verLen);
+    }
+  }
+  ret = dlopen(curName, flag);
+  free(curName);
+  return ret;
+}
+
 static int preInitW(Display *dpy) 
 {
 
@@ -208,13 +237,13 @@ static int preInitW(Display *dpy)
     wrapperPreInit = 1;
     xW.preInitialised = 0;
     xW.initialised = 0;
-    xvhandle = dlopen("libXv.so" XV_SOVERSION, RTLD_LAZY | RTLD_GLOBAL);
+    xvhandle = dlopenversion("libXv.so", XV_SOVERSION, RTLD_LAZY | RTLD_GLOBAL);
     if (!xvhandle) {
-      fprintf(stderr,"XvMCWrapper: Warning! Could not open shared "
-             "library \"libXv.so" XV_SOVERSION "\"\nThis may cause relocation "
-             "errors later.\nError was: \"%s\".\n",dlerror());
+       fprintf(stderr,"XvMCWrapper: Warning! Could not open shared "
+               "library \"libXv.so" XV_SOVERSION "\"\nThis may cause relocation "
+               "errors later.\nError was: \"%s\".\n",dlerror());
     } 
-    handle2 = dlopen("libXvMC.so" XVMC_SOVERSION, RTLD_LAZY | RTLD_GLOBAL);
+    handle2 = dlopenversion("libXvMC.so", XVMC_SOVERSION, RTLD_LAZY | RTLD_GLOBAL);
     if (!handle2) {
        fprintf(stderr,"XvMCWrapper: Could not load XvMC "
                "library \"libXvMC.so" XVMC_SOVERSION "\". Failing\n");
@@ -236,6 +265,8 @@ static void initW(Display *dpy, XvPortID port)
     char *err;
     FILE *configFile; 
     int nameLen = 0;
+    int major,minor,patchLevel,isLocal;
+    char *busID = NULL;
 
     wrapperInit = 1;
     xW.initialised = 0;
@@ -247,45 +278,59 @@ static void initW(Display *dpy, XvPortID port)
      * Will the DDX tell us the client driver name?
      */ 
 
-    xW.XvMCDRIGetClientDriverName = (XvMCDRIGetClientDriverNameP)
-      dlsym(handle2,"XvMCDRIGetClientDriverName");
+    xW.XvMCGetDRInfo = (XvMCGetDRInfoP)
+       dlsym(handle2,"XvMCGetDRInfo");
+
     if ((err = dlerror()) == NULL) {
-      clientName = xW.XvMCDRIGetClientDriverName( dpy, port);
-      if (clientName) nameLen = strlen(clientName);    
-    }
-    if (clientName && (nameLen < BUFLEN-7)) {
-      nameLen += 3;
-      strncpy(nameBuffer,"lib",BUFLEN-1);
-      strncpy(nameBuffer+3, clientName, BUFLEN-4);
-      strncpy(nameBuffer + nameLen, ".so", BUFLEN-nameLen-1);
-      nameBuffer[BUFLEN-1] = 0;
-      XFree(clientName);
-    } else {
+       if (0 == xW.XvMCGetDRInfo( dpy, port, &clientName, &busID, &major, 
+                                   &minor,&patchLevel, &isLocal)) {
+           nameLen = strlen(clientName);
+           XFree(busID);
+           if (!isLocal) {
+               fprintf(stderr,"XvMCWrapper: X server is not local. Cannot run XvMC.\n");
+               XFree(clientName);
+               return;
+           }
+       } else {
+           clientName = NULL;
+       }
+    } 
 
-      /*
-       * No. Try to obtain it from the config file.
-       */
+    if (clientName && (nameLen < BUFLEN-7) && (nameLen > 0)) {
+       nameLen += 3;
+       strncpy(nameBuffer,"lib",BUFLEN-1);
+       strncpy(nameBuffer+3, clientName, BUFLEN-4);
+       strncpy(nameBuffer + nameLen, ".so", BUFLEN-nameLen-1);
+       nameBuffer[BUFLEN-1] = 0;
+       XFree(clientName);
+       handle = dlopenversion(nameBuffer, XVMC_SOVERSION,RTLD_LAZY);
+    } else {
+       /*
+        * No. Try to obtain it from the config file.
+        */
       
+       if (clientName) XFree(clientName);
+
        configFile = fopen(STRS(XVMC_CONFIGDIR) "/XvMCConfig","r");
       
-      xW.initialised = 0;
-      xW.vldextension = 0;
+       xW.initialised = 0;
+       xW.vldextension = 0;
       
-      if (0 == configFile) {
-       fprintf(stderr,"XvMCWrapper: Could not open config file \"%s\".\n",
-               STRS(XVMC_CONFIGDIR) "/XvMCConfig");
-       perror("XvMCWrapper");
-       return;
-      }
+       if (0 == configFile) {
+           fprintf(stderr,"XvMCWrapper: Could not open config file \"%s\".\n",
+                   STRS(XVMC_CONFIGDIR) "/XvMCConfig");
+           perror("XvMCWrapper");
+           return;
+       }
 
-      if (0 == fgets(nameBuffer, BUFLEN, configFile)) {
-       fclose(configFile);
-       fprintf(stderr,"XvMCWrapper: Could not read XvMC library name.\n");
-       perror("XvMCWrapper");
-       return;
-      }
+       if (0 == fgets(nameBuffer, BUFLEN, configFile)) {
+           fclose(configFile);
+           fprintf(stderr,"XvMCWrapper: Could not read XvMC library name.\n");
+           perror("XvMCWrapper");
+           return;
+       }
        
-      fclose(configFile);
+       fclose(configFile);
        if ((tmp = strlen(nameBuffer)) == 0) {
            fprintf(stderr,"XvMCWrapper: Zero length XvMC library name.\n");
            fprintf(stderr,"%s\n",dlerror());
@@ -303,8 +348,8 @@ static void initW(Display *dpy, XvPortID port)
                return;
            }
        }
+       handle = dlopen(nameBuffer,RTLD_LAZY);
     }
-    handle = dlopen(nameBuffer, RTLD_LAZY);
     if (!handle) {
        fprintf(stderr,"XvMCWrapper: Could not load hardware specific XvMC "
                "library \"%s\".\n",nameBuffer);