/* * Given a display pointer and screen number, determine the name of * the DRI driver for the screen. (I.e. "r128", "tdfx", etc). * Return True for success, False for failure. */ 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; }
_X_HIDDEN __GLXDRIdrawable * driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) { struct glx_display *const priv = __glXInitialize(gc->psc->dpy); __GLXDRIdrawable *pdraw; struct glx_screen *psc; if (priv == NULL) return NULL; psc = priv->screens[gc->screen]; if (priv->drawHash == NULL) return NULL; if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { pdraw->refcount ++; return pdraw; } pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable, gc->config); if (pdraw == NULL) { ErrorMessageF("failed to create drawable\n"); return NULL; } if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { (*pdraw->destroyDrawable) (pdraw); return NULL; } pdraw->refcount = 1; return pdraw; }
/* * Given a display pointer and screen number, determine the name of * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc). * Return True for success, False for failure. */ static Bool driGetDriverName(Display * dpy, int scrNum, char **driverName) { int directCapable; Bool b; int event, error; int driverMajor, driverMinor, driverPatch; *driverName = NULL; if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */ 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; } else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */ char *dev; Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev); if (ret) free(dev); return ret; } return False; }
/** * Perform the required libGL-side initialization and call the client-side * driver's \c __driCreateNewScreen function. * * \param dpy Display pointer. * \param scrn Screen number on the display. * \param psc DRI screen information. * \param driDpy DRI display information. * \param createNewScreen Pointer to the client-side driver's * \c __driCreateNewScreen function. * \returns A pointer to the \c __DRIscreen structure returned by * the client-side driver on success, or \c NULL on failure. */ static void * CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc, struct dri_display * driDpy) { void *psp = NULL; drm_handle_t hSAREA; drmAddress pSAREA = MAP_FAILED; char *BusID; __DRIversion ddx_version; __DRIversion dri_version; __DRIversion drm_version; __DRIframebuffer framebuffer; int fd = -1; int status; drm_magic_t magic; drmVersionPtr version; int newlyopened; char *driverName; drm_handle_t hFB; int junk; const __DRIconfig **driver_configs; struct glx_config *visual, *configs = NULL, *visuals = NULL; /* DRI protocol version. */ dri_version.major = driDpy->driMajor; dri_version.minor = driDpy->driMinor; dri_version.patch = driDpy->driPatch; framebuffer.base = MAP_FAILED; framebuffer.dev_priv = NULL; framebuffer.size = 0; if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { ErrorMessageF("XF86DRIOpenConnection failed\n"); goto handle_error; } fd = drmOpenOnce(NULL, BusID, &newlyopened); free(BusID); /* No longer needed */ if (fd < 0) { ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd)); goto handle_error; } if (drmGetMagic(fd, &magic)) { ErrorMessageF("drmGetMagic failed\n"); goto handle_error; } version = drmGetVersion(fd); if (version) { drm_version.major = version->version_major; drm_version.minor = version->version_minor; drm_version.patch = version->version_patchlevel; drmFreeVersion(version); } else { drm_version.major = -1; drm_version.minor = -1; drm_version.patch = -1; } if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) { ErrorMessageF("XF86DRIAuthConnection failed\n"); goto handle_error; } /* Get device name (like "radeon") and the ddx version numbers. * We'll check the version in each DRI driver's "createNewScreen" * function. */ if (!XF86DRIGetClientDriverName(dpy, scrn, &ddx_version.major, &ddx_version.minor, &ddx_version.patch, &driverName)) { ErrorMessageF("XF86DRIGetClientDriverName failed\n"); goto handle_error; } free(driverName); /* No longer needed. */ /* * Get device-specific info. pDevPriv will point to a struct * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that * has information about the screen size, depth, pitch, ancilliary * buffers, DRM mmap handles, etc. */ if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk, &framebuffer.size, &framebuffer.stride, &framebuffer.dev_priv_size, &framebuffer.dev_priv)) { ErrorMessageF("XF86DRIGetDeviceInfo failed\n"); goto handle_error; } framebuffer.width = DisplayWidth(dpy, scrn); framebuffer.height = DisplayHeight(dpy, scrn); /* Map the framebuffer region. */ status = drmMap(fd, hFB, framebuffer.size, (drmAddressPtr) & framebuffer.base); if (status != 0) { ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status)); goto handle_error; } /* Map the SAREA region. Further mmap regions may be setup in * each DRI driver's "createNewScreen" function. */ status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); if (status != 0) { ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status)); goto handle_error; } psp = (*psc->legacy->createNewScreen) (scrn, &ddx_version, &dri_version, &drm_version, &framebuffer, pSAREA, fd, loader_extensions, &driver_configs, psc); if (psp == NULL) { ErrorMessageF("Calling driver entry point failed\n"); goto handle_error; } configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); if (!configs || !visuals) goto handle_error; glx_config_destroy_list(psc->base.configs); psc->base.configs = configs; glx_config_destroy_list(psc->base.visuals); psc->base.visuals = visuals; psc->driver_configs = driver_configs; /* Visuals with depth != screen depth are subject to automatic compositing * in the X server, so DRI1 can't render to them properly. Mark them as * non-conformant to prevent apps from picking them up accidentally. */ for (visual = psc->base.visuals; visual; visual = visual->next) { XVisualInfo template;
static __GLXDRIscreen * driCreateScreen(__GLXscreenConfigs * psc, int screen, __GLXdisplayPrivate * priv) { __GLXDRIscreen *psp; const __DRIconfig **driver_configs; const __DRIextension **extensions; const char *driverName = "swrast"; int i; psp = Xcalloc(1, sizeof *psp); if (psp == NULL) return NULL; psc->driver = driOpenDriver(driverName); if (psc->driver == NULL) goto handle_error; extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); if (extensions == NULL) { ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); goto handle_error; } for (i = 0; extensions[i]; i++) { if (strcmp(extensions[i]->name, __DRI_CORE) == 0) psc->core = (__DRIcoreExtension *) extensions[i]; if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0) psc->swrast = (__DRIswrastExtension *) extensions[i]; } if (psc->core == NULL || psc->swrast == NULL) { ErrorMessageF("core dri extension not found\n"); goto handle_error; } psc->__driScreen = psc->swrast->createNewScreen(screen, loader_extensions, &driver_configs, psc); if (psc->__driScreen == NULL) { ErrorMessageF("failed to create dri screen\n"); goto handle_error; } driBindExtensions(psc); driBindCommonExtensions(psc); psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); psc->driver_configs = driver_configs; psp->destroyScreen = driDestroyScreen; psp->createContext = driCreateContext; psp->createDrawable = driCreateDrawable; psp->swapBuffers = driSwapBuffers; psp->waitX = NULL; psp->waitGL = NULL; return psp; handle_error: Xfree(psp); if (psc->driver) dlclose(psc->driver); ErrorMessageF("reverting to indirect rendering\n"); return NULL; }
/** * Try to \c dlopen the named driver. * * This function adds the "_dri.so" suffix to the driver name and searches the * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in * order to find the driver. * * \param driverName - a name like "i965", "radeon", "nouveau", etc. * * \returns * A handle from \c dlopen, or \c NULL if driver file not found. */ _X_HIDDEN void * driOpenDriver(const char *driverName) { void *glhandle, *handle; const char *libPaths, *p, *next; char realDriverName[200]; int len; /* Attempt to make sure libGL symbols will be visible to the driver */ glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL); libPaths = NULL; if (geteuid() == getuid()) { /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ libPaths = getenv("LIBGL_DRIVERS_PATH"); if (!libPaths) libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */ } if (libPaths == NULL) libPaths = DEFAULT_DRIVER_DIR; handle = NULL; for (p = libPaths; *p; p = next) { next = strchr(p, ':'); if (next == NULL) { len = strlen(p); next = p + len; } else { len = next - p; next++; } #ifdef GLX_USE_TLS snprintf(realDriverName, sizeof realDriverName, "%.*s/tls/%s_dri.so", len, p, driverName); InfoMessageF("OpenDriver: trying %s\n", realDriverName); handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); #endif if (handle == NULL) { snprintf(realDriverName, sizeof realDriverName, "%.*s/%s_dri.so", len, p, driverName); InfoMessageF("OpenDriver: trying %s\n", realDriverName); handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); } if (handle != NULL) break; else InfoMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror()); } if (!handle) ErrorMessageF("unable to load driver: %s_dri.so\n", driverName); if (glhandle) dlclose(glhandle); return handle; }
static __GLXDRIscreen * dri2CreateScreen(__GLXscreenConfigs * psc, int screen, __GLXdisplayPrivate * priv) { const __DRIconfig **driver_configs; const __DRIextension **extensions; const __GLXDRIdisplayPrivate *const pdp = (__GLXDRIdisplayPrivate *) priv->dri2Display; __GLXDRIscreen *psp; char *driverName, *deviceName; drm_magic_t magic; int i; psp = Xmalloc(sizeof *psp); if (psp == NULL) return NULL; if (!DRI2Connect(psc->dpy, RootWindow(psc->dpy, screen), &driverName, &deviceName)) { XFree(psp); return NULL; } psc->driver = driOpenDriver(driverName); if (psc->driver == NULL) { ErrorMessageF("driver pointer missing\n"); goto handle_error; } extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); if (extensions == NULL) { ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); goto handle_error; } for (i = 0; extensions[i]; i++) { if (strcmp(extensions[i]->name, __DRI_CORE) == 0) psc->core = (__DRIcoreExtension *) extensions[i]; if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) psc->dri2 = (__DRIdri2Extension *) extensions[i]; } if (psc->core == NULL || psc->dri2 == NULL) { ErrorMessageF("core dri or dri2 extension not found\n"); goto handle_error; } psc->fd = open(deviceName, O_RDWR); if (psc->fd < 0) { ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); goto handle_error; } if (drmGetMagic(psc->fd, &magic)) { ErrorMessageF("failed to get magic\n"); goto handle_error; } if (!DRI2Authenticate(psc->dpy, RootWindow(psc->dpy, screen), magic)) { ErrorMessageF("failed to authenticate magic %d\n", magic); goto handle_error; } /* If the server does not support the protocol for * DRI2GetBuffersWithFormat, don't supply that interface to the driver. */ psc->__driScreen = psc->dri2->createNewScreen(screen, psc->fd, ((pdp->driMinor < 1) ? loader_extensions_old : loader_extensions), &driver_configs, psc); if (psc->__driScreen == NULL) { ErrorMessageF("failed to create dri screen\n"); goto handle_error; } driBindCommonExtensions(psc); dri2BindExtensions(psc); psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); psc->driver_configs = driver_configs; psp->destroyScreen = dri2DestroyScreen; psp->createContext = dri2CreateContext; psp->createDrawable = dri2CreateDrawable; psp->swapBuffers = dri2SwapBuffers; psp->waitGL = dri2WaitGL; psp->waitX = dri2WaitX; psp->getDrawableMSC = NULL; psp->waitForMSC = NULL; psp->waitForSBC = NULL; psp->setSwapInterval = NULL; psp->getSwapInterval = NULL; if (pdp->driMinor >= 2) { #ifdef X_DRI2GetMSC psp->getDrawableMSC = dri2DrawableGetMSC; #endif #ifdef X_DRI2WaitMSC psp->waitForMSC = dri2WaitForMSC; psp->waitForSBC = dri2WaitForSBC; #endif #ifdef X_DRI2SwapInterval psp->setSwapInterval = dri2SetSwapInterval; psp->getSwapInterval = dri2GetSwapInterval; #endif #if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) __glXEnableDirectExtension(psc, "GLX_OML_sync_control"); #endif } /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always * available.*/ psp->copySubBuffer = dri2CopySubBuffer; __glXEnableDirectExtension(psc, "GLX_MESA_copy_sub_buffer"); Xfree(driverName); Xfree(deviceName); return psp; handle_error: Xfree(driverName); Xfree(deviceName); XFree(psp); /* FIXME: clean up here */ return NULL; }
/** * Try to \c dlopen the named driver. * * This function adds the "_dri.so" suffix to the driver name and searches the * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in * order to find the driver. * * \param driverName - a name like "tdfx", "i810", "mga", etc. * * \returns * A handle from \c dlopen, or \c NULL if driver file not found. */ static __DRIdriver *OpenDriver(const char *driverName) { char *libPaths = NULL; char libDir[1000]; int i; __DRIdriver *driver; /* First, search Drivers list to see if we've already opened this driver */ for (driver = Drivers; driver; driver = driver->next) { if (strcmp(driver->name, driverName) == 0) { /* found it */ return driver; } } if (geteuid() == getuid()) { /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ libPaths = getenv("LIBGL_DRIVERS_PATH"); if (!libPaths) libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */ } if (!libPaths) libPaths = DEFAULT_DRIVER_DIR; for ( i = 0 ; ExtractDir(i, libPaths, 1000, libDir) != 0 ; i++ ) { char realDriverName[200]; void *handle = NULL; /* If TLS support is enabled, try to open the TLS version of the driver * binary first. If that fails, try the non-TLS version. */ #ifdef GLX_USE_TLS snprintf(realDriverName, 200, "%s/tls/%s_dri.so", libDir, driverName); InfoMessageF("OpenDriver: trying %s\n", realDriverName); handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); #endif if ( handle == NULL ) { snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName); InfoMessageF("OpenDriver: trying %s\n", realDriverName); handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); } if ( handle != NULL ) { /* allocate __DRIdriver struct */ driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver)); if (!driver) return NULL; /* out of memory! */ /* init the struct */ driver->name = __glXstrdup(driverName); if (!driver->name) { Xfree(driver); return NULL; /* out of memory! */ } driver->createNewScreenFunc = (PFNCREATENEWSCREENFUNC) dlsym(handle, createNewScreenName); if ( driver->createNewScreenFunc == NULL ) { /* If the driver doesn't have this symbol then something's * really, really wrong. */ ErrorMessageF("%s not defined in %s_dri.so!\n" "Your driver may be too old for this libGL.\n", createNewScreenName, driverName); Xfree(driver); dlclose(handle); continue; } driver->handle = handle; /* put at head of linked list */ 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; }