/* * Copyright (c) 2008-2009 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #if DRI2 #include "mesa_dri2.h" #include #endif typedef void SetDllHandle( void * driver_dll_handle ); static void * _vdp_backend_dll; static void * _vdp_trace_dll; static void * _vdp_driver_dll; static VdpDeviceCreateX11 * _vdp_imp_device_create_x11_proc; #if defined(__GNUC__) static void _vdp_close_driver(void) __attribute__((destructor)); #endif #if DEBUG static void _vdp_wrapper_error_breakpoint(char const * file, int line, char const * function) { fprintf(stderr, "VDPAU wrapper: Error detected at %s:%d %s()\n", file, line, function); } #define _VDP_ERROR_BREAKPOINT() _vdp_wrapper_error_breakpoint(__FILE__, __LINE__, __FUNCTION__) #else #define _VDP_ERROR_BREAKPOINT() #endif #define DRIVER_LIB_FORMAT "%slibvdpau_%s.so%s" static char * _vdp_get_driver_name_from_dri2( Display * display, int screen ) { char * driver_name = NULL; #if DRI2 Window root = RootWindow(display, screen); int event_base, error_base; int major, minor; char * device_name; if (!_vdp_DRI2QueryExtension(display, &event_base, &error_base)) { return NULL; } if (!_vdp_DRI2QueryVersion(display, &major, &minor) || (major < 1 || (major == 1 && minor < 2))) { return NULL; } if (!_vdp_DRI2Connect(display, root, &driver_name, &device_name)) { return NULL; } XFree(device_name); #endif /* DRI2 */ return driver_name; } static VdpStatus _vdp_open_driver( Display * display, int screen) { char const * vdpau_driver; char * vdpau_driver_dri2 = NULL; char vdpau_driver_lib[PATH_MAX]; char const * vdpau_trace; char const * func_name; vdpau_driver = getenv("VDPAU_DRIVER"); if (!vdpau_driver) { vdpau_driver = vdpau_driver_dri2 = _vdp_get_driver_name_from_dri2(display, screen); } if (!vdpau_driver) { vdpau_driver = "nvidia"; } if (snprintf(vdpau_driver_lib, sizeof(vdpau_driver_lib), DRIVER_LIB_FORMAT, VDPAU_MODULEDIR "/", vdpau_driver, ".1") >= sizeof(vdpau_driver_lib)) { fprintf(stderr, "Failed to construct driver path: path too long\n"); if (vdpau_driver_dri2) { XFree(vdpau_driver_dri2); vdpau_driver_dri2 = NULL; } _VDP_ERROR_BREAKPOINT(); return VDP_STATUS_NO_IMPLEMENTATION; } _vdp_driver_dll = dlopen(vdpau_driver_lib, RTLD_NOW | RTLD_GLOBAL); if (!_vdp_driver_dll) { /* Try again using the old path, which is guaranteed to fit in PATH_MAX * if the complete path fit above. */ snprintf(vdpau_driver_lib, sizeof(vdpau_driver_lib), DRIVER_LIB_FORMAT, "", vdpau_driver, ""); _vdp_driver_dll = dlopen(vdpau_driver_lib, RTLD_NOW | RTLD_GLOBAL); } if (vdpau_driver_dri2) { XFree(vdpau_driver_dri2); vdpau_driver_dri2 = NULL; } if (!_vdp_driver_dll) { fprintf(stderr, "Failed to open VDPAU backend %s\n", dlerror()); _VDP_ERROR_BREAKPOINT(); return VDP_STATUS_NO_IMPLEMENTATION; } _vdp_backend_dll = _vdp_driver_dll; vdpau_trace = getenv("VDPAU_TRACE"); if (vdpau_trace && atoi(vdpau_trace)) { SetDllHandle * set_dll_handle; _vdp_trace_dll = dlopen(VDPAU_MODULEDIR "/libvdpau_trace.so.1", RTLD_NOW | RTLD_GLOBAL); if (!_vdp_trace_dll) { fprintf(stderr, "Failed to open VDPAU trace library %s\n", dlerror()); _VDP_ERROR_BREAKPOINT(); return VDP_STATUS_NO_IMPLEMENTATION; } set_dll_handle = (SetDllHandle*)dlsym( _vdp_trace_dll, "vdp_trace_set_backend_handle" ); if (!set_dll_handle) { fprintf(stderr, "%s\n", dlerror()); _VDP_ERROR_BREAKPOINT(); return VDP_STATUS_NO_IMPLEMENTATION; } set_dll_handle(_vdp_backend_dll); _vdp_backend_dll = _vdp_trace_dll; func_name = "vdp_trace_device_create_x11"; } else { func_name = "vdp_imp_device_create_x11"; } _vdp_imp_device_create_x11_proc = (VdpDeviceCreateX11*)dlsym( _vdp_backend_dll, func_name ); if (!_vdp_imp_device_create_x11_proc) { fprintf(stderr, "%s\n", dlerror()); _VDP_ERROR_BREAKPOINT(); return VDP_STATUS_NO_IMPLEMENTATION; } return VDP_STATUS_OK; } static void _vdp_close_driver(void) { if (_vdp_driver_dll) { dlclose(_vdp_driver_dll); _vdp_driver_dll = NULL; } if (_vdp_trace_dll) { dlclose(_vdp_trace_dll); _vdp_trace_dll = NULL; } _vdp_backend_dll = NULL; _vdp_imp_device_create_x11_proc = NULL; } VdpStatus vdp_device_create_x11( Display * display, int screen, /* output parameters follow */ VdpDevice * device, VdpGetProcAddress * * get_proc_address ) { VdpStatus status; if (!_vdp_imp_device_create_x11_proc) { status = _vdp_open_driver(display, screen); if (status != VDP_STATUS_OK) { _vdp_close_driver(); return status; } } return _vdp_imp_device_create_x11_proc( display, screen, device, get_proc_address ); }