revert the DRI2 commits
[mesa.git] / src / glx / x11 / dri_glx.c
1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
32 *
33 */
34
35 #ifdef GLX_DIRECT_RENDERING
36
37 #include <unistd.h>
38 #include <X11/Xlibint.h>
39 #include <X11/extensions/Xext.h>
40 #include <X11/extensions/extutil.h>
41 #include "glheader.h"
42 #include "glxclient.h"
43 #include "xf86dri.h"
44 #include "sarea.h"
45 #include <stdio.h>
46 #include <dlfcn.h>
47 #include "dri_glx.h"
48 #include <sys/types.h>
49 #include <stdarg.h>
50
51 #ifndef RTLD_NOW
52 #define RTLD_NOW 0
53 #endif
54 #ifndef RTLD_GLOBAL
55 #define RTLD_GLOBAL 0
56 #endif
57
58
59 #ifndef DEFAULT_DRIVER_DIR
60 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
61 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
62 #endif
63
64 static __DRIdriver *Drivers = NULL;
65
66
67 /*
68 * printf wrappers
69 */
70
71 static void InfoMessageF(const char *f, ...)
72 {
73 va_list args;
74 const char *env;
75
76 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
77 fprintf(stderr, "libGL: ");
78 va_start(args, f);
79 vfprintf(stderr, f, args);
80 va_end(args);
81 }
82 }
83
84 /**
85 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
86 */
87 static void ErrorMessageF(const char *f, ...)
88 {
89 va_list args;
90 const char *env;
91
92 if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
93 fprintf(stderr, "libGL error: ");
94 va_start(args, f);
95 vfprintf(stderr, f, args);
96 va_end(args);
97 }
98 }
99
100
101 /**
102 * Extract the ith directory path out of a colon-separated list of paths. No
103 * more than \c dirLen characters, including the terminating \c NUL, will be
104 * written to \c dir.
105 *
106 * \param index Index of path to extract (starting at zero)
107 * \param paths The colon-separated list of paths
108 * \param dirLen Maximum length of result to store in \c dir
109 * \param dir Buffer to hold the extracted directory path
110 *
111 * \returns
112 * The number of characters that would have been written to \c dir had there
113 * been enough room. This does not include the terminating \c NUL. When
114 * extraction fails, zero will be returned.
115 *
116 * \todo
117 * It seems like this function could be rewritten to use \c strchr.
118 */
119 static size_t
120 ExtractDir(int index, const char *paths, int dirLen, char *dir)
121 {
122 int i, len;
123 const char *start, *end;
124
125 /* find ith colon */
126 start = paths;
127 i = 0;
128 while (i < index) {
129 if (*start == ':') {
130 i++;
131 start++;
132 }
133 else if (*start == 0) {
134 /* end of string and couldn't find ith colon */
135 dir[0] = 0;
136 return 0;
137 }
138 else {
139 start++;
140 }
141 }
142
143 while (*start == ':')
144 start++;
145
146 /* find next colon, or end of string */
147 end = start + 1;
148 while (*end != ':' && *end != 0) {
149 end++;
150 }
151
152 /* copy string between <start> and <end> into result string */
153 len = end - start;
154 if (len > dirLen - 1)
155 len = dirLen - 1;
156 strncpy(dir, start, len);
157 dir[len] = 0;
158
159 return( end - start );
160 }
161
162
163 /**
164 * Versioned name of the expected \c __driCreateNewScreen function.
165 *
166 * The version of the last incompatible loader/driver inteface change is
167 * appended to the name of the \c __driCreateNewScreen function. This
168 * prevents loaders from trying to load drivers that are too old.
169 *
170 * \todo
171 * Create a macro or something so that this is automatically updated.
172 */
173 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
174
175
176 /**
177 * Try to \c dlopen the named driver.
178 *
179 * This function adds the "_dri.so" suffix to the driver name and searches the
180 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
181 * order to find the driver.
182 *
183 * \param driverName - a name like "tdfx", "i810", "mga", etc.
184 *
185 * \returns
186 * A handle from \c dlopen, or \c NULL if driver file not found.
187 */
188 static __DRIdriver *OpenDriver(const char *driverName)
189 {
190 void *glhandle = NULL;
191 char *libPaths = NULL;
192 char libDir[1000];
193 int i;
194 __DRIdriver *driver;
195
196 /* First, search Drivers list to see if we've already opened this driver */
197 for (driver = Drivers; driver; driver = driver->next) {
198 if (strcmp(driver->name, driverName) == 0) {
199 /* found it */
200 return driver;
201 }
202 }
203
204 /* Attempt to make sure libGL symbols will be visible to the driver */
205 glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
206
207 if (geteuid() == getuid()) {
208 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
209 libPaths = getenv("LIBGL_DRIVERS_PATH");
210 if (!libPaths)
211 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
212 }
213 if (!libPaths)
214 libPaths = DEFAULT_DRIVER_DIR;
215
216 for ( i = 0 ; ExtractDir(i, libPaths, 1000, libDir) != 0 ; i++ ) {
217 char realDriverName[200];
218 void *handle = NULL;
219
220
221 /* If TLS support is enabled, try to open the TLS version of the driver
222 * binary first. If that fails, try the non-TLS version.
223 */
224 #ifdef GLX_USE_TLS
225 snprintf(realDriverName, 200, "%s/tls/%s_dri.so", libDir, driverName);
226 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
227 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
228 #endif
229
230 if ( handle == NULL ) {
231 snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
232 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
233 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
234 }
235
236 if ( handle != NULL ) {
237 /* allocate __DRIdriver struct */
238 driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver));
239 if (!driver)
240 break; /* out of memory! */
241 /* init the struct */
242 driver->name = __glXstrdup(driverName);
243 if (!driver->name) {
244 Xfree(driver);
245 driver = NULL;
246 break; /* out of memory! */
247 }
248
249 driver->createNewScreenFunc = (PFNCREATENEWSCREENFUNC)
250 dlsym(handle, createNewScreenName);
251
252 if ( driver->createNewScreenFunc == NULL ) {
253 /* If the driver doesn't have this symbol then something's
254 * really, really wrong.
255 */
256 ErrorMessageF("%s not defined in %s_dri.so!\n"
257 "Your driver may be too old for this libGL.\n",
258 createNewScreenName, driverName);
259 Xfree(driver);
260 driver = NULL;
261 dlclose(handle);
262 continue;
263 }
264 driver->handle = handle;
265 /* put at head of linked list */
266 driver->next = Drivers;
267 Drivers = driver;
268 break;
269 }
270 else {
271 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
272 }
273 }
274
275 if (!driver)
276 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
277
278 if (glhandle)
279 dlclose(glhandle);
280
281 return driver;
282 }
283
284
285 /*
286 * Given a display pointer and screen number, determine the name of
287 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
288 * Return True for success, False for failure.
289 */
290 static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
291 {
292 int directCapable;
293 Bool b;
294 int driverMajor, driverMinor, driverPatch;
295
296 *driverName = NULL;
297
298 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
299 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
300 return False;
301 }
302 if (!directCapable) {
303 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
304 return False;
305 }
306
307 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
308 &driverPatch, driverName);
309 if (!b) {
310 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
311 return False;
312 }
313
314 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
315 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
316
317 return True;
318 }
319
320
321 /*
322 * Given a display pointer and screen number, return a __DRIdriver handle.
323 * Return NULL if anything goes wrong.
324 */
325 __DRIdriver *driGetDriver(Display *dpy, int scrNum)
326 {
327 char *driverName;
328 if (GetDriverName(dpy, scrNum, &driverName)) {
329 __DRIdriver *ret;
330 ret = OpenDriver(driverName);
331 if (driverName)
332 Xfree(driverName);
333 return ret;
334 }
335 return NULL;
336 }
337
338
339 /*
340 * Exported function for querying the DRI driver for a given screen.
341 *
342 * The returned char pointer points to a static array that will be
343 * overwritten by subsequent calls.
344 */
345 PUBLIC const char *glXGetScreenDriver (Display *dpy, int scrNum) {
346 static char ret[32];
347 char *driverName;
348 if (GetDriverName(dpy, scrNum, &driverName)) {
349 int len;
350 if (!driverName)
351 return NULL;
352 len = strlen (driverName);
353 if (len >= 31)
354 return NULL;
355 memcpy (ret, driverName, len+1);
356 Xfree(driverName);
357 return ret;
358 }
359 return NULL;
360 }
361
362
363 /*
364 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
365 *
366 * The returned char pointer points directly into the driver. Therefore
367 * it should be treated as a constant.
368 *
369 * If the driver was not found or does not support configuration NULL is
370 * returned.
371 *
372 * Note: The driver remains opened after this function returns.
373 */
374 PUBLIC const char *glXGetDriverConfig (const char *driverName) {
375 __DRIdriver *driver = OpenDriver (driverName);
376 if (driver)
377 return dlsym (driver->handle, "__driConfigOptions");
378 else
379 return NULL;
380 }
381
382
383 /* Called from __glXFreeDisplayPrivate.
384 */
385 static void driDestroyDisplay(Display *dpy, void *private)
386 {
387 __DRIdisplayPrivate *pdpyp = (__DRIdisplayPrivate *)private;
388
389 if (pdpyp) {
390 const int numScreens = ScreenCount(dpy);
391 int i;
392 for (i = 0; i < numScreens; i++) {
393 if (pdpyp->libraryHandles[i]) {
394 __DRIdriver *driver, *prev;
395
396 /* Remove driver from Drivers list */
397 for (prev = NULL, driver = Drivers; driver;
398 prev = driver, driver = driver->next) {
399 if (driver->handle == pdpyp->libraryHandles[i]) {
400 if (prev)
401 prev->next = driver->next;
402 else
403 Drivers = driver->next;
404
405 Xfree(driver->name);
406 Xfree(driver);
407 break;
408 }
409 }
410
411 dlclose(pdpyp->libraryHandles[i]);
412 }
413 }
414 Xfree(pdpyp->libraryHandles);
415 Xfree(pdpyp);
416 }
417 }
418
419
420 /*
421 * Allocate, initialize and return a __DRIdisplayPrivate object.
422 * This is called from __glXInitialize() when we are given a new
423 * display pointer.
424 */
425 void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
426 {
427 const int numScreens = ScreenCount(dpy);
428 __DRIdisplayPrivate *pdpyp;
429 int eventBase, errorBase;
430 int major, minor, patch;
431 int scrn;
432
433 /* Initialize these fields to NULL in case we fail.
434 * If we don't do this we may later get segfaults trying to free random
435 * addresses when the display is closed.
436 */
437 pdisp->private = NULL;
438 pdisp->destroyDisplay = NULL;
439
440 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
441 return NULL;
442 }
443
444 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
445 return NULL;
446 }
447
448 pdpyp = (__DRIdisplayPrivate *)Xmalloc(sizeof(__DRIdisplayPrivate));
449 if (!pdpyp) {
450 return NULL;
451 }
452
453 pdpyp->driMajor = major;
454 pdpyp->driMinor = minor;
455 pdpyp->driPatch = patch;
456
457 pdisp->destroyDisplay = driDestroyDisplay;
458
459 /* allocate array of pointers to createNewScreen funcs */
460 pdisp->createNewScreen = (PFNCREATENEWSCREENFUNC *)
461 Xmalloc(numScreens * sizeof(void *));
462 if (!pdisp->createNewScreen) {
463 Xfree(pdpyp);
464 return NULL;
465 }
466
467 /* allocate array of library handles */
468 pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*));
469 if (!pdpyp->libraryHandles) {
470 Xfree(pdisp->createNewScreen);
471 Xfree(pdpyp);
472 return NULL;
473 }
474
475 /* dynamically discover DRI drivers for all screens, saving each
476 * driver's "__driCreateScreen" function pointer. That's the bootstrap
477 * entrypoint for all DRI drivers.
478 */
479 for (scrn = 0; scrn < numScreens; scrn++) {
480 __DRIdriver *driver = driGetDriver(dpy, scrn);
481 if (driver) {
482 pdisp->createNewScreen[scrn] = driver->createNewScreenFunc;
483 pdpyp->libraryHandles[scrn] = driver->handle;
484 }
485 else {
486 pdisp->createNewScreen[scrn] = NULL;
487 pdpyp->libraryHandles[scrn] = NULL;
488 }
489 }
490
491 return (void *)pdpyp;
492 }
493
494 #endif /* GLX_DIRECT_RENDERING */