restore FASTCALL stuff
[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 /* $XFree86: xc/lib/GL/dri/dri_glx.c,v 1.14 2003/07/16 00:54:00 dawes Exp $ */
28
29 /*
30 * Authors:
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
33 *
34 */
35
36 #ifdef GLX_DIRECT_RENDERING
37
38 #include <unistd.h>
39 #include <X11/Xlibint.h>
40 #include <X11/extensions/Xext.h>
41 #include <X11/extensions/extutil.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 the Imakefile */
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 static void ErrorMessageF(const char *f, ...)
85 {
86 va_list args;
87
88 if (getenv("LIBGL_DEBUG")) {
89 fprintf(stderr, "libGL error: ");
90 va_start(args, f);
91 vfprintf(stderr, f, args);
92 va_end(args);
93 }
94 }
95
96
97 /**
98 * Extract the ith directory path out of a colon-separated list of paths. No
99 * more than \c dirLen characters, including the terminating \c NUL, will be
100 * written to \c dir.
101 *
102 * \param index Index of path to extract (starting at zero)
103 * \param paths The colon-separated list of paths
104 * \param dirLen Maximum length of result to store in \c dir
105 * \param dir Buffer to hold the extracted directory path
106 *
107 * \returns
108 * The number of characters that would have been written to \c dir had there
109 * been enough room. This does not include the terminating \c NUL. When
110 * extraction fails, zero will be returned.
111 *
112 * \todo
113 * It seems like this function could be rewritten to use \c strchr.
114 */
115 static size_t
116 ExtractDir(int index, const char *paths, int dirLen, char *dir)
117 {
118 int i, len;
119 const char *start, *end;
120
121 /* find ith colon */
122 start = paths;
123 i = 0;
124 while (i < index) {
125 if (*start == ':') {
126 i++;
127 start++;
128 }
129 else if (*start == 0) {
130 /* end of string and couldn't find ith colon */
131 dir[0] = 0;
132 return 0;
133 }
134 else {
135 start++;
136 }
137 }
138
139 while (*start == ':')
140 start++;
141
142 /* find next colon, or end of string */
143 end = start + 1;
144 while (*end != ':' && *end != 0) {
145 end++;
146 }
147
148 /* copy string between <start> and <end> into result string */
149 len = end - start;
150 if (len > dirLen - 1)
151 len = dirLen - 1;
152 strncpy(dir, start, len);
153 dir[len] = 0;
154
155 return( end - start );
156 }
157
158
159 /**
160 * Versioned name of the expected \c __driCreateNewScreen function.
161 *
162 * The version of the last incompatible loader/driver inteface change is
163 * appended to the name of the \c __driCreateNewScreen function. This
164 * prevents loaders from trying to load drivers that are too old.
165 *
166 * \todo
167 * Create a macro or something so that this is automatically updated.
168 */
169 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
170
171
172 /**
173 * Try to \c dlopen the named driver.
174 *
175 * This function adds the "_dri.so" suffix to the driver name and searches the
176 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
177 * order to find the driver.
178 *
179 * \param driverName - a name like "tdfx", "i810", "mga", etc.
180 *
181 * \returns
182 * A handle from \c dlopen, or \c NULL if driver file not found.
183 */
184 static __DRIdriver *OpenDriver(const char *driverName)
185 {
186 char *libPaths = NULL;
187 char libDir[1000];
188 int i;
189 __DRIdriver *driver;
190
191 /* First, search Drivers list to see if we've already opened this driver */
192 for (driver = Drivers; driver; driver = driver->next) {
193 if (strcmp(driver->name, driverName) == 0) {
194 /* found it */
195 return driver;
196 }
197 }
198
199 if (geteuid() == getuid()) {
200 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
201 libPaths = getenv("LIBGL_DRIVERS_PATH");
202 if (!libPaths)
203 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
204 }
205 if (!libPaths)
206 libPaths = DEFAULT_DRIVER_DIR;
207
208 for ( i = 0 ; ExtractDir(i, libPaths, 1000, libDir) != 0 ; i++ ) {
209 char realDriverName[200];
210 void *handle = NULL;
211
212
213 /* If TLS support is enabled, try to open the TLS version of the driver
214 * binary first. If that fails, try the non-TLS version.
215 */
216 #ifdef GLX_USE_TLS
217 snprintf(realDriverName, 200, "%s/tls/%s_dri.so", libDir, driverName);
218 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
219 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
220 #endif
221
222 if ( handle == NULL ) {
223 snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
224 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
225 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
226 }
227
228 if ( handle != NULL ) {
229 /* allocate __DRIdriver struct */
230 driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver));
231 if (!driver)
232 return NULL; /* out of memory! */
233 /* init the struct */
234 driver->name = __glXstrdup(driverName);
235 if (!driver->name) {
236 Xfree(driver);
237 return NULL; /* out of memory! */
238 }
239
240 driver->createNewScreenFunc = (PFNCREATENEWSCREENFUNC)
241 dlsym(handle, createNewScreenName);
242
243 if ( driver->createNewScreenFunc == NULL ) {
244 /* If the driver doesn't have this symbol then something's
245 * really, really wrong.
246 */
247 ErrorMessageF("%s not defined in %s_dri.so!\n"
248 "Your driver may be too old for this libGL.\n",
249 createNewScreenName, driverName);
250 Xfree(driver);
251 dlclose(handle);
252 continue;
253 }
254 driver->handle = handle;
255 /* put at head of linked list */
256 driver->next = Drivers;
257 Drivers = driver;
258 return driver;
259 }
260 else {
261 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
262 }
263 }
264
265 ErrorMessageF("unable to find driver: %s_dri.so\n", driverName);
266 return NULL;
267 }
268
269
270 /*
271 * Given a display pointer and screen number, determine the name of
272 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
273 * Return True for success, False for failure.
274 */
275 static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
276 {
277 int directCapable;
278 Bool b;
279 int driverMajor, driverMinor, driverPatch;
280
281 *driverName = NULL;
282
283 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
284 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
285 return False;
286 }
287 if (!directCapable) {
288 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
289 return False;
290 }
291
292 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
293 &driverPatch, driverName);
294 if (!b) {
295 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
296 return False;
297 }
298
299 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
300 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
301
302 return True;
303 }
304
305
306 /*
307 * Given a display pointer and screen number, return a __DRIdriver handle.
308 * Return NULL if anything goes wrong.
309 */
310 __DRIdriver *driGetDriver(Display *dpy, int scrNum)
311 {
312 char *driverName;
313 if (GetDriverName(dpy, scrNum, &driverName)) {
314 __DRIdriver *ret;
315 ret = OpenDriver(driverName);
316 if (driverName)
317 Xfree(driverName);
318 return ret;
319 }
320 return NULL;
321 }
322
323
324 /*
325 * Exported function for querying the DRI driver for a given screen.
326 *
327 * The returned char pointer points to a static array that will be
328 * overwritten by subsequent calls.
329 */
330 const char *glXGetScreenDriver (Display *dpy, int scrNum) {
331 static char ret[32];
332 char *driverName;
333 if (GetDriverName(dpy, scrNum, &driverName)) {
334 int len;
335 if (!driverName)
336 return NULL;
337 len = strlen (driverName);
338 if (len >= 31)
339 return NULL;
340 memcpy (ret, driverName, len+1);
341 Xfree(driverName);
342 return ret;
343 }
344 return NULL;
345 }
346
347
348 /*
349 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
350 *
351 * The returned char pointer points directly into the driver. Therefore
352 * it should be treated as a constant.
353 *
354 * If the driver was not found or does not support configuration NULL is
355 * returned.
356 *
357 * Note: The driver remains opened after this function returns.
358 */
359 const char *glXGetDriverConfig (const char *driverName) {
360 __DRIdriver *driver = OpenDriver (driverName);
361 if (driver)
362 return dlsym (driver->handle, "__driConfigOptions");
363 else
364 return NULL;
365 }
366
367
368 /* This function isn't currently used.
369 */
370 static void driDestroyDisplay(Display *dpy, void *private)
371 {
372 __DRIdisplayPrivate *pdpyp = (__DRIdisplayPrivate *)private;
373
374 if (pdpyp) {
375 const int numScreens = ScreenCount(dpy);
376 int i;
377 for (i = 0; i < numScreens; i++) {
378 if (pdpyp->libraryHandles[i])
379 dlclose(pdpyp->libraryHandles[i]);
380 }
381 Xfree(pdpyp->libraryHandles);
382 Xfree(pdpyp);
383 }
384 }
385
386
387 /*
388 * Allocate, initialize and return a __DRIdisplayPrivate object.
389 * This is called from __glXInitialize() when we are given a new
390 * display pointer.
391 */
392 void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
393 {
394 const int numScreens = ScreenCount(dpy);
395 __DRIdisplayPrivate *pdpyp;
396 int eventBase, errorBase;
397 int major, minor, patch;
398 int scrn;
399
400 /* Initialize these fields to NULL in case we fail.
401 * If we don't do this we may later get segfaults trying to free random
402 * addresses when the display is closed.
403 */
404 pdisp->private = NULL;
405 pdisp->destroyDisplay = NULL;
406
407 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
408 return NULL;
409 }
410
411 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
412 return NULL;
413 }
414
415 pdpyp = (__DRIdisplayPrivate *)Xmalloc(sizeof(__DRIdisplayPrivate));
416 if (!pdpyp) {
417 return NULL;
418 }
419
420 pdpyp->driMajor = major;
421 pdpyp->driMinor = minor;
422 pdpyp->driPatch = patch;
423
424 pdisp->destroyDisplay = driDestroyDisplay;
425
426 /* allocate array of pointers to createNewScreen funcs */
427 pdisp->createNewScreen = (PFNCREATENEWSCREENFUNC *)
428 Xmalloc(numScreens * sizeof(void *));
429 if (!pdisp->createNewScreen) {
430 Xfree(pdpyp);
431 return NULL;
432 }
433
434 /* allocate array of library handles */
435 pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*));
436 if (!pdpyp->libraryHandles) {
437 Xfree(pdisp->createNewScreen);
438 Xfree(pdpyp);
439 return NULL;
440 }
441
442 /* dynamically discover DRI drivers for all screens, saving each
443 * driver's "__driCreateScreen" function pointer. That's the bootstrap
444 * entrypoint for all DRI drivers.
445 */
446 for (scrn = 0; scrn < numScreens; scrn++) {
447 __DRIdriver *driver = driGetDriver(dpy, scrn);
448 if (driver) {
449 pdisp->createNewScreen[scrn] = driver->createNewScreenFunc;
450 pdpyp->libraryHandles[scrn] = driver->handle;
451 }
452 else {
453 pdisp->createNewScreen[scrn] = NULL;
454 pdpyp->libraryHandles[scrn] = NULL;
455 }
456 }
457
458 return (void *)pdpyp;
459 }
460
461 #endif /* GLX_DIRECT_RENDERING */