/* * 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 "sysdeps.h" #ifdef HAVE_NVCTRL #include #define NEED_REPLIES #include #include #include #include #include #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 XEXT_GENERATE_CLOSE_DISPLAY(close_display, nvctrl_ext_info) 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 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); } static 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; } static Bool VA_NVCTRLGetClientDriverName(Display *dpy, int screen, char **clientDriverName) { int ddxDriverMajorVersion, ddxDriverMinorVersion, ddxDriverPatchVersion; 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) { ddxDriverMajorVersion = v; if (*(str = end) == '.') { v = strtoul(str + 1, &end, 10); if (end && end != str && (*end == '.' || *end == '\0')) { ddxDriverMinorVersion = v; if (*(str = end) == '.') { v = strtoul(str + 1, &end, 10); if (end && end != str && *end == '\0') { ddxDriverPatchVersion = v; } } } } } Xfree(nvidia_driver_version); (void) ddxDriverMajorVersion; (void) ddxDriverMinorVersion; (void) ddxDriverPatchVersion; *clientDriverName = strdup("nvidia"); return True; } VAStatus va_NVCTRL_GetDriverNames( VADisplayContextP pDisplayContext, char **drivers, unsigned *num_drivers ) { VADriverContextP ctx = pDisplayContext->pDriverContext; int direct_capable; if (!VA_NVCTRLQueryDirectRenderingCapable(ctx->native_dpy, ctx->x11_screen, &direct_capable) || !direct_capable) return VA_STATUS_ERROR_UNKNOWN; if (!VA_NVCTRLGetClientDriverName(ctx->native_dpy, ctx->x11_screen, drivers)) return VA_STATUS_ERROR_UNKNOWN; *num_drivers = 1; return VA_STATUS_SUCCESS; } #endif