Make the transition to script-genereated GLX code easier.
[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 "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 #ifdef BUILT_IN_DRI_DRIVER
59
60 extern void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
61 int numConfigs, __GLXvisualConfig *config);
62
63
64 #else /* BUILT_IN_DRI_DRIVER */
65
66
67 #ifndef DEFAULT_DRIVER_DIR
68 /* this is normally defined in the Imakefile */
69 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
70 #endif
71
72 static __DRIdriver *Drivers = NULL;
73
74
75 /*
76 * printf wrappers
77 */
78
79 static void InfoMessageF(const char *f, ...)
80 {
81 va_list args;
82 const char *env;
83
84 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
85 fprintf(stderr, "libGL: ");
86 va_start(args, f);
87 vfprintf(stderr, f, args);
88 va_end(args);
89 }
90 }
91
92 static void ErrorMessageF(const char *f, ...)
93 {
94 va_list args;
95
96 if (getenv("LIBGL_DEBUG")) {
97 fprintf(stderr, "libGL error: ");
98 va_start(args, f);
99 vfprintf(stderr, f, args);
100 va_end(args);
101 }
102 }
103
104
105 /*
106 * We'll save a pointer to this function when we couldn't find a
107 * direct rendering driver for a given screen.
108 */
109 static void *DummyCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
110 int numConfigs, __GLXvisualConfig *config)
111 {
112 (void) dpy;
113 (void) scrn;
114 (void) psc;
115 (void) numConfigs;
116 (void) config;
117 return NULL;
118 }
119
120
121
122 /*
123 * Extract the ith directory path out of a colon-separated list of
124 * paths.
125 * Input:
126 * index - index of path to extract (starting at zero)
127 * paths - the colon-separated list of paths
128 * dirLen - max length of result to store in <dir>
129 * Output:
130 * dir - the extracted directory path, dir[0] will be zero when
131 * extraction fails.
132 */
133 static void ExtractDir(int index, const char *paths, int dirLen, char *dir)
134 {
135 int i, len;
136 const char *start, *end;
137
138 /* find ith colon */
139 start = paths;
140 i = 0;
141 while (i < index) {
142 if (*start == ':') {
143 i++;
144 start++;
145 }
146 else if (*start == 0) {
147 /* end of string and couldn't find ith colon */
148 dir[0] = 0;
149 return;
150 }
151 else {
152 start++;
153 }
154 }
155
156 while (*start == ':')
157 start++;
158
159 /* find next colon, or end of string */
160 end = start + 1;
161 while (*end != ':' && *end != 0) {
162 end++;
163 }
164
165 /* copy string between <start> and <end> into result string */
166 len = end - start;
167 if (len > dirLen - 1)
168 len = dirLen - 1;
169 strncpy(dir, start, len);
170 dir[len] = 0;
171 }
172
173
174 /*
175 * Try to dlopen() the named driver. This function adds the
176 * "_dri.so" suffix to the driver name and searches the
177 * directories specified by the LIBGL_DRIVERS_PATH env var
178 * in order to find the driver.
179 * Input:
180 * driverName - a name like "tdfx", "i810", "mga", etc.
181 * Return:
182 * handle from dlopen, or NULL if driver file not found.
183 */
184 static __DRIdriver *OpenDriver(const char *driverName)
185 {
186 char *libPaths = NULL;
187 int i;
188 __DRIdriver *driver;
189
190 /* First, search Drivers list to see if we've already opened this driver */
191 for (driver = Drivers; driver; driver = driver->next) {
192 if (strcmp(driver->name, driverName) == 0) {
193 /* found it */
194 return driver;
195 }
196 }
197
198 if (geteuid() == getuid()) {
199 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
200 libPaths = getenv("LIBGL_DRIVERS_PATH");
201 if (!libPaths)
202 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
203 }
204 if (!libPaths)
205 libPaths = DEFAULT_DRIVER_DIR;
206
207 for (i = 0; ; i++) {
208 char libDir[1000], realDriverName[200];
209 void *handle;
210 ExtractDir(i, libPaths, 1000, libDir);
211 if (!libDir[0])
212 break; /* ran out of paths to search */
213 snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
214 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
215 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
216 if (handle) {
217 /* allocate __DRIdriver struct */
218 driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver));
219 if (!driver)
220 return NULL; /* out of memory! */
221 /* init the struct */
222 driver->name = __glXstrdup(driverName);
223 if (!driver->name) {
224 Xfree(driver);
225 return NULL; /* out of memory! */
226 }
227
228 driver->createScreenFunc = (CreateScreenFunc)
229 dlsym(handle, "__driCreateScreen");
230 driver->createNewScreenFunc = (CreateNewScreenFunc)
231 dlsym(handle, "__driCreateNewScreen");
232
233 if ( (driver->createScreenFunc == NULL)
234 && (driver->createNewScreenFunc == NULL) ) {
235 /* If the driver doesn't have this symbol then something's
236 * really, really wrong.
237 */
238 ErrorMessageF("Neither __driCreateScreen or __driCreateNewScreen "
239 "are defined in %s_dri.so!\n", driverName);
240 Xfree(driver);
241 dlclose(handle);
242 continue;
243 }
244 driver->handle = handle;
245 /* put at head of linked list */
246 driver->next = Drivers;
247 Drivers = driver;
248 return driver;
249 }
250 else {
251 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
252 }
253 }
254
255 ErrorMessageF("unable to find driver: %s_dri.so\n", driverName);
256 return NULL;
257 }
258
259
260 /*
261 * Given a display pointer and screen number, determine the name of
262 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
263 * Return True for success, False for failure.
264 */
265 static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
266 {
267 int directCapable;
268 Bool b;
269 int driverMajor, driverMinor, driverPatch;
270
271 *driverName = NULL;
272
273 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
274 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
275 return False;
276 }
277 if (!directCapable) {
278 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
279 return False;
280 }
281
282 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
283 &driverPatch, driverName);
284 if (!b) {
285 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
286 return False;
287 }
288
289 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
290 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
291
292 return True;
293 }
294
295
296 /*
297 * Given a display pointer and screen number, return a __DRIdriver handle.
298 * Return NULL if anything goes wrong.
299 */
300 __DRIdriver *driGetDriver(Display *dpy, int scrNum)
301 {
302 char *driverName;
303 if (GetDriverName(dpy, scrNum, &driverName)) {
304 __DRIdriver *ret;
305 ret = OpenDriver(driverName);
306 if (driverName)
307 Xfree(driverName);
308 return ret;
309 }
310 return NULL;
311 }
312
313
314 /*
315 * Exported function for querying the DRI driver for a given screen.
316 *
317 * The returned char pointer points to a static array that will be
318 * overwritten by subsequent calls.
319 */
320 const char *glXGetScreenDriver (Display *dpy, int scrNum) {
321 static char ret[32];
322 char *driverName;
323 if (GetDriverName(dpy, scrNum, &driverName)) {
324 int len;
325 if (!driverName)
326 return NULL;
327 len = strlen (driverName);
328 if (len >= 31)
329 return NULL;
330 memcpy (ret, driverName, len+1);
331 Xfree(driverName);
332 return ret;
333 }
334 return NULL;
335 }
336
337
338 /*
339 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
340 *
341 * The returned char pointer points directly into the driver. Therefore
342 * it should be treated as a constant.
343 *
344 * If the driver was not found or does not support configuration NULL is
345 * returned.
346 *
347 * Note: The driver remains opened after this function returns.
348 */
349 const char *glXGetDriverConfig (const char *driverName) {
350 __DRIdriver *driver = OpenDriver (driverName);
351 if (driver)
352 return dlsym (driver->handle, "__driConfigOptions");
353 else
354 return NULL;
355 }
356
357
358 #endif /* BUILT_IN_DRI_DRIVER */
359
360
361 /* This function isn't currently used.
362 */
363 static void driDestroyDisplay(Display *dpy, void *private)
364 {
365 __DRIdisplayPrivate *pdpyp = (__DRIdisplayPrivate *)private;
366
367 if (pdpyp) {
368 const int numScreens = ScreenCount(dpy);
369 int i;
370 for (i = 0; i < numScreens; i++) {
371 if (pdpyp->libraryHandles[i])
372 dlclose(pdpyp->libraryHandles[i]);
373 }
374 Xfree(pdpyp->libraryHandles);
375 Xfree(pdpyp);
376 }
377 }
378
379
380 /*
381 * Allocate, initialize and return a __DRIdisplayPrivate object.
382 * This is called from __glXInitialize() when we are given a new
383 * display pointer.
384 */
385 void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
386 {
387 const int numScreens = ScreenCount(dpy);
388 __DRIdisplayPrivate *pdpyp;
389 int eventBase, errorBase;
390 int major, minor, patch;
391 int scrn;
392
393 /* Initialize these fields to NULL in case we fail.
394 * If we don't do this we may later get segfaults trying to free random
395 * addresses when the display is closed.
396 */
397 pdisp->private = NULL;
398 pdisp->destroyDisplay = NULL;
399 pdisp->createScreen = NULL;
400
401 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
402 return NULL;
403 }
404
405 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
406 return NULL;
407 }
408
409 pdpyp = (__DRIdisplayPrivate *)Xmalloc(sizeof(__DRIdisplayPrivate));
410 if (!pdpyp) {
411 return NULL;
412 }
413
414 pdpyp->driMajor = major;
415 pdpyp->driMinor = minor;
416 pdpyp->driPatch = patch;
417
418 pdisp->destroyDisplay = driDestroyDisplay;
419
420 /* allocate array of pointers to createScreen funcs */
421 pdisp->createScreen = (CreateScreenFunc *) Xmalloc(numScreens * sizeof(void *));
422 if (!pdisp->createScreen) {
423 Xfree(pdpyp);
424 return NULL;
425 }
426
427 /* allocate array of pointers to createScreen funcs */
428 pdisp->createNewScreen = (CreateNewScreenFunc *) Xmalloc(numScreens * sizeof(void *));
429 if (!pdisp->createNewScreen) {
430 Xfree(pdisp->createScreen);
431 Xfree(pdpyp);
432 return NULL;
433 }
434
435 /* allocate array of library handles */
436 pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*));
437 if (!pdpyp->libraryHandles) {
438 Xfree(pdisp->createNewScreen);
439 Xfree(pdisp->createScreen);
440 Xfree(pdpyp);
441 return NULL;
442 }
443
444 #ifdef BUILT_IN_DRI_DRIVER
445 /* we'll statically bind to the built-in __driCreateScreen function */
446 for (scrn = 0; scrn < numScreens; scrn++) {
447 pdisp->createScreen[scrn] = __driCreateScreen;
448 pdisp->createNewScreen[scrn] = NULL;
449 pdpyp->libraryHandles[scrn] = NULL;
450 }
451
452 #else
453 /* dynamically discover DRI drivers for all screens, saving each
454 * driver's "__driCreateScreen" function pointer. That's the bootstrap
455 * entrypoint for all DRI drivers.
456 */
457 for (scrn = 0; scrn < numScreens; scrn++) {
458 __DRIdriver *driver = driGetDriver(dpy, scrn);
459 if (driver) {
460 pdisp->createScreen[scrn] = driver->createScreenFunc;
461 pdisp->createNewScreen[scrn] = driver->createNewScreenFunc;
462 pdpyp->libraryHandles[scrn] = driver->handle;
463 }
464 else {
465 pdisp->createScreen[scrn] = DummyCreateScreen;
466 pdisp->createNewScreen[scrn] = NULL;
467 pdpyp->libraryHandles[scrn] = NULL;
468 }
469 }
470 #endif
471
472 return (void *)pdpyp;
473 }
474
475 #endif /* GLX_DIRECT_RENDERING */