#ifdef GLX_DIRECT_RENDERING
#include <unistd.h>
#include <X11/Xlibint.h>
#include <X11/extensions/Xext.h>
#include "extutil.h"
#include "glxclient.h"
#include "xf86dri.h"
#include "sarea.h"
#include <stdio.h>
#include <dlfcn.h>
#include "dri_glx.h"
#include <sys/types.h>
#include <stdarg.h>
#ifndef RTLD_NOW
#define RTLD_NOW 0
#endif
#ifndef RTLD_GLOBAL
#define RTLD_GLOBAL 0
#endif
#ifdef BUILT_IN_DRI_DRIVER
extern void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
int numConfigs, __GLXvisualConfig *config);
#else
#ifndef DEFAULT_DRIVER_DIR
#define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
#endif
static __DRIdriver *Drivers = NULL;
static void InfoMessageF(const char *f, ...)
{
va_list args;
const char *env;
if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
fprintf(stderr, "libGL: ");
va_start(args, f);
vfprintf(stderr, f, args);
va_end(args);
}
}
static void ErrorMessageF(const char *f, ...)
{
va_list args;
if (getenv("LIBGL_DEBUG")) {
fprintf(stderr, "libGL error: ");
va_start(args, f);
vfprintf(stderr, f, args);
va_end(args);
}
}
static void *DummyCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
int numConfigs, __GLXvisualConfig *config)
{
(void) dpy;
(void) scrn;
(void) psc;
(void) numConfigs;
(void) config;
return NULL;
}
static void ExtractDir(int index, const char *paths, int dirLen, char *dir)
{
int i, len;
const char *start, *end;
start = paths;
i = 0;
while (i < index) {
if (*start == ':') {
i++;
start++;
}
else if (*start == 0) {
dir[0] = 0;
return;
}
else {
start++;
}
}
while (*start == ':')
start++;
end = start + 1;
while (*end != ':' && *end != 0) {
end++;
}
len = end - start;
if (len > dirLen - 1)
len = dirLen - 1;
strncpy(dir, start, len);
dir[len] = 0;
}
static __DRIdriver *OpenDriver(const char *driverName)
{
char *libPaths = NULL;
int i;
__DRIdriver *driver;
for (driver = Drivers; driver; driver = driver->next) {
if (strcmp(driver->name, driverName) == 0) {
return driver;
}
}
if (geteuid() == getuid()) {
libPaths = getenv("LIBGL_DRIVERS_PATH");
if (!libPaths)
libPaths = getenv("LIBGL_DRIVERS_DIR");
}
if (!libPaths)
libPaths = DEFAULT_DRIVER_DIR;
for (i = 0; ; i++) {
char libDir[1000], realDriverName[200];
void *handle;
ExtractDir(i, libPaths, 1000, libDir);
if (!libDir[0])
break;
snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
InfoMessageF("OpenDriver: trying %s\n", realDriverName);
handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
if (handle) {
driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver));
if (!driver)
return NULL;
driver->name = __glXstrdup(driverName);
if (!driver->name) {
Xfree(driver);
return NULL;
}
driver->createScreenFunc = (CreateScreenFunc)
dlsym(handle, "__driCreateScreen");
if (!driver->createScreenFunc) {
ErrorMessageF("__driCreateScreen() not defined in %s_dri.so!\n",
driverName);
Xfree(driver);
dlclose(handle);
continue;
}
driver->handle = handle;
driver->next = Drivers;
Drivers = driver;
return driver;
}
else {
ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
}
}
ErrorMessageF("unable to find driver: %s_dri.so\n", driverName);
return NULL;
}
static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
{
int directCapable;
Bool b;
int driverMajor, driverMinor, driverPatch;
*driverName = NULL;
if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
return False;
}
if (!directCapable) {
ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
return False;
}
b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
&driverPatch, driverName);
if (!b) {
ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
return False;
}
InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
driverMajor, driverMinor, driverPatch, *driverName, scrNum);
return True;
}
__DRIdriver *driGetDriver(Display *dpy, int scrNum)
{
char *driverName;
if (GetDriverName(dpy, scrNum, &driverName)) {
__DRIdriver *ret;
ret = OpenDriver(driverName);
if (driverName)
Xfree(driverName);
return ret;
}
return NULL;
}
#endif
static void driDestroyDisplay(Display *dpy, void *private)
{
__DRIdisplayPrivate *pdpyp = (__DRIdisplayPrivate *)private;
if (pdpyp) {
const int numScreens = ScreenCount(dpy);
int i;
for (i = 0; i < numScreens; i++) {
if (pdpyp->libraryHandles[i])
dlclose(pdpyp->libraryHandles[i]);
}
Xfree(pdpyp->libraryHandles);
Xfree(pdpyp);
}
}
void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
{
const int numScreens = ScreenCount(dpy);
__DRIdisplayPrivate *pdpyp;
int eventBase, errorBase;
int major, minor, patch;
int scrn;
pdisp->private = NULL;
pdisp->destroyDisplay = NULL;
pdisp->createScreen = NULL;
if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
return NULL;
}
if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
return NULL;
}
pdpyp = (__DRIdisplayPrivate *)Xmalloc(sizeof(__DRIdisplayPrivate));
if (!pdpyp) {
return NULL;
}
pdpyp->driMajor = major;
pdpyp->driMinor = minor;
pdpyp->driPatch = patch;
pdisp->destroyDisplay = driDestroyDisplay;
pdisp->createScreen = (CreateScreenFunc *) Xmalloc(numScreens * sizeof(void *));
if (!pdisp->createScreen) {
XFree(pdpyp);
return NULL;
}
pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*));
if (!pdpyp->libraryHandles) {
Xfree(pdisp->createScreen);
XFree(pdpyp);
return NULL;
}
#ifdef BUILT_IN_DRI_DRIVER
for (scrn = 0; scrn < numScreens; scrn++) {
pdisp->createScreen[scrn] = __driCreateScreen;
pdpyp->libraryHandles[scrn] = NULL;
}
#else
for (scrn = 0; scrn < numScreens; scrn++) {
__DRIdriver *driver = driGetDriver(dpy, scrn);
if (driver) {
pdisp->createScreen[scrn] = driver->createScreenFunc;
pdpyp->libraryHandles[scrn] = driver->handle;
}
else {
pdisp->createScreen[scrn] = DummyCreateScreen;
pdpyp->libraryHandles[scrn] = NULL;
}
}
#endif
return (void *)pdpyp;
}
#endif