Fix NVIDIA driver detection.
authorGwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Wed, 8 Jul 2009 07:56:05 +0000 (07:56 +0000)
committerAustin Yuan <shengquan.yuan@intel.com>
Fri, 14 Aug 2009 14:20:58 +0000 (22:20 +0800)
Signed-off-by: Austin Yuan <shengquan.yuan@intel.com>
src/x11/Makefile.am
src/x11/va_nvctrl.c [new file with mode: 0644]
src/x11/va_nvctrl.h [new file with mode: 0644]
src/x11/va_x11.c

index 8d1c160..c70380d 100644 (file)
@@ -25,6 +25,6 @@ noinst_LTLIBRARIES = libva_x11.la
 libva_x11includedir = ${includedir}/va
 libva_x11include_HEADERS = va_x11.h va_dri.h va_dri2.h va_dricommon.h
 
-libva_x11_la_SOURCES = va_x11.c va_dri.c va_dri2.c va_dricommon.c dri2_util.c dri1_util.c
+libva_x11_la_SOURCES = va_x11.c va_dri.c va_dri2.c va_dricommon.c dri2_util.c dri1_util.c va_nvctrl.c
 
-EXTRA_DIST = va_dristr.h va_dri2str.h va_dri2tokens.h
+EXTRA_DIST = va_dristr.h va_dri2str.h va_dri2tokens.h va_nvctrl.h
diff --git a/src/x11/va_nvctrl.c b/src/x11/va_nvctrl.c
new file mode 100644 (file)
index 0000000..46fcca5
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2008 NVIDIA, Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE 1
+#include <string.h>
+
+#define NEED_REPLIES
+#include <stdlib.h>
+#include <X11/Xlibint.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+#include "va_nvctrl.h"
+
+#define NV_CONTROL_ERRORS 0
+#define NV_CONTROL_EVENTS 5
+#define NV_CONTROL_NAME "NV-CONTROL"
+
+#define NV_CTRL_TARGET_TYPE_X_SCREEN   0
+#define NV_CTRL_TARGET_TYPE_GPU        1
+#define NV_CTRL_TARGET_TYPE_FRAMELOCK  2
+#define NV_CTRL_TARGET_TYPE_VCSC       3 /* Visual Computing System */
+
+#define NV_CTRL_STRING_NVIDIA_DRIVER_VERSION                    3  /* R--G */
+
+#define X_nvCtrlQueryExtension                      0
+#define X_nvCtrlIsNv                                1
+#define X_nvCtrlQueryStringAttribute                4
+
+typedef struct {
+    CARD8 reqType;
+    CARD8 nvReqType;
+    CARD16 length B16;
+} xnvCtrlQueryExtensionReq;
+#define sz_xnvCtrlQueryExtensionReq 4
+
+typedef struct {
+    BYTE type;   /* X_Reply */
+    CARD8 padb1;
+    CARD16 sequenceNumber B16;
+    CARD32 length B32;
+    CARD16 major B16;
+    CARD16 minor B16;
+    CARD32 padl4 B32;
+    CARD32 padl5 B32;
+    CARD32 padl6 B32;
+    CARD32 padl7 B32;
+    CARD32 padl8 B32;
+} xnvCtrlQueryExtensionReply;
+#define sz_xnvCtrlQueryExtensionReply 32
+
+typedef struct {
+    CARD8 reqType;
+    CARD8 nvReqType;
+    CARD16 length B16;
+    CARD32 screen B32;
+} xnvCtrlIsNvReq;
+#define sz_xnvCtrlIsNvReq 8
+
+typedef struct {
+    BYTE type;   /* X_Reply */
+    CARD8 padb1;
+    CARD16 sequenceNumber B16;
+    CARD32 length B32;
+    CARD32 isnv B32;
+    CARD32 padl4 B32;
+    CARD32 padl5 B32;
+    CARD32 padl6 B32;
+    CARD32 padl7 B32;
+    CARD32 padl8 B32;
+} xnvCtrlIsNvReply;
+#define sz_xnvCtrlIsNvReply 32
+
+typedef struct {
+    CARD8 reqType;
+    CARD8 nvReqType;
+    CARD16 length B16;
+    CARD16 target_id B16;    /* X screen number or GPU number */
+    CARD16 target_type B16;  /* X screen or GPU */
+    CARD32 display_mask B32;
+    CARD32 attribute B32;
+} xnvCtrlQueryStringAttributeReq;
+#define sz_xnvCtrlQueryStringAttributeReq 16
+
+typedef struct {
+    BYTE type;
+    BYTE pad0;
+    CARD16 sequenceNumber B16;
+    CARD32 length B32;
+    CARD32 flags B32;
+    CARD32 n B32;    /* Length of string */
+    CARD32 pad4 B32;
+    CARD32 pad5 B32;
+    CARD32 pad6 B32;
+    CARD32 pad7 B32;
+} xnvCtrlQueryStringAttributeReply;
+#define sz_xnvCtrlQueryStringAttributeReply 32
+
+#define NVCTRL_EXT_NEED_CHECK          (XPointer)(~0)
+#define NVCTRL_EXT_NEED_NOTHING        (XPointer)(0)
+#define NVCTRL_EXT_NEED_TARGET_SWAP    (XPointer)(1)
+
+static XExtensionInfo _nvctrl_ext_info_data;
+static XExtensionInfo *nvctrl_ext_info = &_nvctrl_ext_info_data;
+static /* const */ char *nvctrl_extension_name = NV_CONTROL_NAME;
+
+#define XNVCTRLCheckExtension(dpy,i,val) \
+  XextCheckExtension (dpy, i, nvctrl_extension_name, val)
+#define XNVCTRLSimpleCheckExtension(dpy,i) \
+  XextSimpleCheckExtension (dpy, i, nvctrl_extension_name)
+
+static int close_display();
+static /* const */ XExtensionHooks nvctrl_extension_hooks = {
+    NULL,                               /* create_gc */
+    NULL,                               /* copy_gc */
+    NULL,                               /* flush_gc */
+    NULL,                               /* free_gc */
+    NULL,                               /* create_font */
+    NULL,                               /* free_font */
+    close_display,                      /* close_display */
+    NULL,                               /* wire_to_event */
+    NULL,                               /* event_to_wire */
+    NULL,                               /* error */
+    NULL,                               /* error_string */
+};
+
+static XEXT_GENERATE_FIND_DISPLAY (find_display, nvctrl_ext_info,
+                                   nvctrl_extension_name, 
+                                   &nvctrl_extension_hooks,
+                                   NV_CONTROL_EVENTS, NVCTRL_EXT_NEED_CHECK)
+
+static XEXT_GENERATE_CLOSE_DISPLAY (close_display, nvctrl_ext_info)
+
+static Bool XNVCTRLQueryVersion (Display *dpy, int *major, int *minor);
+
+/*
+ * NV-CONTROL versions 1.8 and 1.9 pack the target_type and target_id
+ * fields in reversed order.  In order to talk to one of these servers,
+ * we need to swap these fields.
+ */
+static void XNVCTRLCheckTargetData(Display *dpy, XExtDisplayInfo *info,
+                                   int *target_type, int *target_id)
+{
+    /* Find out what the server's NV-CONTROL version is and
+     * setup for swapping if we need to.
+     */
+    if (info->data == NVCTRL_EXT_NEED_CHECK) {
+        int major, minor;
+
+        if (XNVCTRLQueryVersion(dpy, &major, &minor)) {
+            if (major == 1 &&
+                (minor == 8 || minor == 9)) {
+                info->data = NVCTRL_EXT_NEED_TARGET_SWAP;
+            } else {
+                info->data = NVCTRL_EXT_NEED_NOTHING;
+            }
+        } else {
+            info->data = NVCTRL_EXT_NEED_NOTHING;
+        }
+    }
+
+    /* We need to swap the target_type and target_id */
+    if (info->data == NVCTRL_EXT_NEED_TARGET_SWAP) {
+        int tmp;
+        tmp = *target_type;
+        *target_type = *target_id;
+        *target_id = tmp;
+    }
+}
+
+
+static Bool XNVCTRLQueryExtension (
+    Display *dpy,
+    int *event_basep,
+    int *error_basep
+){
+    XExtDisplayInfo *info = find_display (dpy);
+
+    if (XextHasExtension(info)) {
+        if (event_basep) *event_basep = info->codes->first_event;
+        if (error_basep) *error_basep = info->codes->first_error;
+        return True;
+    } else {
+        return False;
+    }
+}
+
+
+static Bool XNVCTRLQueryVersion (
+    Display *dpy,
+    int *major,
+    int *minor
+){
+    XExtDisplayInfo *info = find_display (dpy);
+    xnvCtrlQueryExtensionReply rep;
+    xnvCtrlQueryExtensionReq   *req;
+
+    if(!XextHasExtension(info))
+        return False;
+
+    XNVCTRLCheckExtension (dpy, info, False);
+
+    LockDisplay (dpy);
+    GetReq (nvCtrlQueryExtension, req);
+    req->reqType = info->codes->major_opcode;
+    req->nvReqType = X_nvCtrlQueryExtension;
+    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
+        UnlockDisplay (dpy);
+        SyncHandle ();
+        return False;
+    }
+    if (major) *major = rep.major;
+    if (minor) *minor = rep.minor;
+    UnlockDisplay (dpy);
+    SyncHandle ();
+    return True;
+}
+
+
+static Bool XNVCTRLIsNvScreen (
+    Display *dpy,
+    int screen
+){
+    XExtDisplayInfo *info = find_display (dpy);
+    xnvCtrlIsNvReply rep;
+    xnvCtrlIsNvReq   *req;
+    Bool isnv;
+
+    if(!XextHasExtension(info))
+        return False;
+
+    XNVCTRLCheckExtension (dpy, info, False);
+
+    LockDisplay (dpy);
+    GetReq (nvCtrlIsNv, req);
+    req->reqType = info->codes->major_opcode;
+    req->nvReqType = X_nvCtrlIsNv;
+    req->screen = screen;
+    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
+        UnlockDisplay (dpy);
+        SyncHandle ();
+        return False;
+    }
+    isnv = rep.isnv;
+    UnlockDisplay (dpy);
+    SyncHandle ();
+    return isnv;
+}
+
+
+static Bool XNVCTRLQueryTargetStringAttribute (
+    Display *dpy,
+    int target_type,
+    int target_id,
+    unsigned int display_mask,
+    unsigned int attribute,
+    char **ptr
+){
+    XExtDisplayInfo *info = find_display (dpy);
+    xnvCtrlQueryStringAttributeReply rep;
+    xnvCtrlQueryStringAttributeReq   *req;
+    Bool exists;
+    int length, numbytes, slop;
+
+    if (!ptr) return False;
+
+    if(!XextHasExtension(info))
+        return False;
+
+    XNVCTRLCheckExtension (dpy, info, False);
+    XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
+
+    LockDisplay (dpy);
+    GetReq (nvCtrlQueryStringAttribute, req);
+    req->reqType = info->codes->major_opcode;
+    req->nvReqType = X_nvCtrlQueryStringAttribute;
+    req->target_type = target_type;
+    req->target_id = target_id;
+    req->display_mask = display_mask;
+    req->attribute = attribute;
+    if (!_XReply (dpy, (xReply *) &rep, 0, False)) {
+        UnlockDisplay (dpy);
+        SyncHandle ();
+        return False;
+    }
+    length = rep.length;
+    numbytes = rep.n;
+    slop = numbytes & 3;
+    *ptr = (char *) Xmalloc(numbytes);
+    if (! *ptr) {
+        _XEatData(dpy, length);
+        UnlockDisplay (dpy);
+        SyncHandle ();
+        return False;
+    } else {
+        _XRead(dpy, (char *) *ptr, numbytes);
+        if (slop) _XEatData(dpy, 4-slop);
+    }
+    exists = rep.flags;
+    UnlockDisplay (dpy);
+    SyncHandle ();
+    return exists;
+}
+
+static Bool XNVCTRLQueryStringAttribute (
+    Display *dpy,
+    int screen,
+    unsigned int display_mask,
+    unsigned int attribute,
+    char **ptr
+){
+    return XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
+                                             screen, display_mask,
+                                             attribute, ptr);
+}
+
+
+Bool VA_NVCTRLQueryDirectRenderingCapable( Display *dpy, int screen,
+    Bool *isCapable )
+{
+    int event_base;
+    int error_base;
+
+    if (isCapable)
+        *isCapable = False;
+
+    if (!XNVCTRLQueryExtension(dpy, &event_base, &error_base))
+        return False;
+
+    if (isCapable && XNVCTRLIsNvScreen(dpy, screen))
+        *isCapable = True;
+
+    return True;
+}
+
+Bool VA_NVCTRLGetClientDriverName( Display *dpy, int screen,
+    int *ddxDriverMajorVersion, int *ddxDriverMinorVersion,
+    int *ddxDriverPatchVersion, char **clientDriverName )
+{
+    if (ddxDriverMajorVersion)
+        *ddxDriverMajorVersion = 0;
+    if (ddxDriverMinorVersion)
+        *ddxDriverMinorVersion = 0;
+    if (ddxDriverPatchVersion)
+        *ddxDriverPatchVersion = 0;
+    if (clientDriverName)
+        *clientDriverName = NULL;
+
+    char *nvidia_driver_version = NULL;
+    if (!XNVCTRLQueryStringAttribute(dpy, screen, 0, NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, &nvidia_driver_version))
+        return False;
+
+    char *end, *str = nvidia_driver_version;
+    unsigned long v = strtoul(str, &end, 10);
+    if (end && end != str) {
+        if (ddxDriverMajorVersion)
+            *ddxDriverMajorVersion = v;
+        if (*(str = end) == '.') {
+            v = strtoul(str + 1, &end, 10);
+            if (end && end != str && *end == '\0') {
+                if (ddxDriverMinorVersion)
+                    *ddxDriverMinorVersion = v;
+            }
+        }
+    }
+    Xfree(nvidia_driver_version);
+
+    if (clientDriverName)
+        *clientDriverName = strdup("nvidia");
+
+    return True;
+}
diff --git a/src/x11/va_nvctrl.h b/src/x11/va_nvctrl.h
new file mode 100644 (file)
index 0000000..c137b86
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008 NVIDIA, Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef VA_NVCTRLLIB_H
+#define VA_NVCTRLLIB_H
+
+#include <X11/Xlib.h>
+
+Bool VA_NVCTRLQueryDirectRenderingCapable( Display *dpy, int screen,
+    Bool *isCapable );
+
+Bool VA_NVCTRLGetClientDriverName( Display *dpy, int screen,
+    int *ddxDriverMajorVersion, int *ddxDriverMinorVersion,
+    int *ddxDriverPatchVersion, char **clientDriverName );
+
+#endif /* VA_NVCTRLLIB_H */
index a196d3d..ec0bbc8 100644 (file)
@@ -30,6 +30,7 @@
 #include "va_dri.h"
 #include "va_dri2.h"
 #include "va_dricommon.h"
+#include "va_nvctrl.h"
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
@@ -125,6 +126,57 @@ static VAStatus va_DRIGetDriverName (
     return VA_STATUS_SUCCESS;
 }
 
+static VAStatus va_NVCTRL_GetDriverName (
+    VADisplayContextP pDisplayContext,
+    char **driver_name
+)
+{
+    VADriverContextP ctx = pDisplayContext->pDriverContext;
+    VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;
+    int direct_capable;
+    int driver_major;
+    int driver_minor;
+    int driver_patch;
+    Bool result = True;
+    char *nvidia_driver_name = NULL;
+
+    if (result)
+    {
+        result = VA_NVCTRLQueryDirectRenderingCapable(ctx->x11_dpy, ctx->x11_screen, &direct_capable);
+        if (!result)
+        {
+            va_errorMessage("VA_NVCTRLQueryDirectRenderingCapable failed\n");
+        }
+    }
+    if (result)
+    {
+        result = direct_capable;
+        if (!result)
+        {
+            va_errorMessage("VA_NVCTRLQueryDirectRenderingCapable returned false\n");
+        }
+    }
+    if (result)
+    {
+        result = VA_NVCTRLGetClientDriverName(ctx->x11_dpy, ctx->x11_screen, &driver_major, &driver_minor,
+                                              &driver_patch, &nvidia_driver_name);
+        if (!result)
+        {
+            va_errorMessage("VA_NVCTRLGetClientDriverName returned false\n");
+        }
+    }
+    if (result)
+    {
+        vaStatus = VA_STATUS_SUCCESS;
+        va_infoMessage("va_NVCTRL_GetDriverName: %d.%d.%d %s (screen %d)\n",
+                       driver_major, driver_minor, driver_patch,
+                       nvidia_driver_name, ctx->x11_screen);
+       if (driver_name)
+            *driver_name = nvidia_driver_name;
+    }
+    return vaStatus;
+}
+
 static VAStatus va_DisplayContextGetDriverName (
     VADisplayContextP pDisplayContext,
     char **driver_name
@@ -147,6 +199,8 @@ static VAStatus va_DisplayContextGetDriverName (
     vaStatus = va_DRI2GetDriverName(pDisplayContext, driver_name);
     if (vaStatus != VA_STATUS_SUCCESS)
         vaStatus = va_DRIGetDriverName(pDisplayContext, driver_name);
+    if (vaStatus != VA_STATUS_SUCCESS)
+        vaStatus = va_NVCTRL_GetDriverName(pDisplayContext, driver_name);
    
     return vaStatus;
 }