egl: When EGL_DRIVER is set, do not add other drivers.
[mesa.git] / src / egl / main / egldriver.c
1 /**
2 * Functions for choosing and opening/loading device drivers.
3 */
4
5
6 #include <assert.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include "eglstring.h"
12 #include "egldefines.h"
13 #include "egldisplay.h"
14 #include "egldriver.h"
15 #include "egllog.h"
16 #include "eglmutex.h"
17
18 #if defined(_EGL_OS_UNIX)
19 #include <dlfcn.h>
20 #include <sys/types.h>
21 #include <dirent.h>
22 #include <unistd.h>
23 #endif
24
25
26 typedef struct _egl_module {
27 char *Path;
28 _EGLMain_t BuiltIn;
29 void *Handle;
30 _EGLDriver *Driver;
31 } _EGLModule;
32
33 static _EGL_DECLARE_MUTEX(_eglModuleMutex);
34 static _EGLArray *_eglModules;
35
36 const struct {
37 const char *name;
38 _EGLMain_t main;
39 } _eglBuiltInDrivers[] = {
40 #ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
41 { "egl_gallium", _eglBuiltInDriverGALLIUM },
42 #endif
43 #ifdef _EGL_BUILT_IN_DRIVER_DRI2
44 { "egl_dri2", _eglBuiltInDriverDRI2 },
45 #endif
46 #ifdef _EGL_BUILT_IN_DRIVER_GLX
47 { "egl_glx", _eglBuiltInDriverGLX },
48 #endif
49 { NULL, NULL }
50 };
51
52 /**
53 * Wrappers for dlopen/dlclose()
54 */
55 #if defined(_EGL_OS_WINDOWS)
56
57
58 typedef HMODULE lib_handle;
59
60 static HMODULE
61 open_library(const char *filename)
62 {
63 return LoadLibrary(filename);
64 }
65
66 static void
67 close_library(HMODULE lib)
68 {
69 FreeLibrary(lib);
70 }
71
72
73 static const char *
74 library_suffix(void)
75 {
76 return ".dll";
77 }
78
79
80 #elif defined(_EGL_OS_UNIX)
81
82
83 typedef void * lib_handle;
84
85 static void *
86 open_library(const char *filename)
87 {
88 return dlopen(filename, RTLD_LAZY);
89 }
90
91 static void
92 close_library(void *lib)
93 {
94 dlclose(lib);
95 }
96
97
98 static const char *
99 library_suffix(void)
100 {
101 return ".so";
102 }
103
104
105 #endif
106
107
108 /**
109 * Open the named driver and find its bootstrap function: _eglMain().
110 */
111 static _EGLMain_t
112 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
113 {
114 lib_handle lib;
115 _EGLMain_t mainFunc = NULL;
116 const char *error = "unknown error";
117
118 assert(driverPath);
119
120 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
121 lib = open_library(driverPath);
122
123 #if defined(_EGL_OS_WINDOWS)
124 /* XXX untested */
125 if (lib)
126 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
127 #elif defined(_EGL_OS_UNIX)
128 if (lib) {
129 union {
130 _EGLMain_t func;
131 void *ptr;
132 } tmp = { NULL };
133 /* direct cast gives a warning when compiled with -pedantic */
134 tmp.ptr = dlsym(lib, "_eglMain");
135 mainFunc = tmp.func;
136 if (!mainFunc)
137 error = dlerror();
138 }
139 else {
140 error = dlerror();
141 }
142 #endif
143
144 if (!lib) {
145 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
146 driverPath, error);
147 return NULL;
148 }
149
150 if (!mainFunc) {
151 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
152 driverPath, error);
153 if (lib)
154 close_library(lib);
155 return NULL;
156 }
157
158 *handle = lib;
159 return mainFunc;
160 }
161
162
163 /**
164 * Load a module and create the driver object.
165 */
166 static EGLBoolean
167 _eglLoadModule(_EGLModule *mod)
168 {
169 _EGLMain_t mainFunc;
170 lib_handle lib;
171 _EGLDriver *drv;
172
173 if (mod->Driver)
174 return EGL_TRUE;
175
176 if (mod->BuiltIn) {
177 lib = (lib_handle) NULL;
178 mainFunc = mod->BuiltIn;
179 }
180 else {
181 mainFunc = _eglOpenLibrary(mod->Path, &lib);
182 if (!mainFunc)
183 return EGL_FALSE;
184 }
185
186 drv = mainFunc(NULL);
187 if (!drv) {
188 if (lib)
189 close_library(lib);
190 return EGL_FALSE;
191 }
192
193 if (!drv->Name) {
194 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
195 drv->Name = "UNNAMED";
196 }
197
198 mod->Handle = (void *) lib;
199 mod->Driver = drv;
200
201 return EGL_TRUE;
202 }
203
204
205 /**
206 * Unload a module.
207 */
208 static void
209 _eglUnloadModule(_EGLModule *mod)
210 {
211 #if defined(_EGL_OS_UNIX)
212 /* destroy the driver */
213 if (mod->Driver && mod->Driver->Unload)
214 mod->Driver->Unload(mod->Driver);
215
216 /*
217 * XXX At this point (atexit), the module might be the last reference to
218 * libEGL. Closing the module might unmap libEGL and give problems.
219 */
220 #if 0
221 if (mod->Handle)
222 close_library(mod->Handle);
223 #endif
224 #elif defined(_EGL_OS_WINDOWS)
225 /* XXX Windows unloads DLLs before atexit */
226 #endif
227
228 mod->Driver = NULL;
229 mod->Handle = NULL;
230 }
231
232
233 /**
234 * Add a module to the module array.
235 */
236 static _EGLModule *
237 _eglAddModule(const char *path)
238 {
239 _EGLModule *mod;
240 EGLint i;
241
242 if (!_eglModules) {
243 _eglModules = _eglCreateArray("Module", 8);
244 if (!_eglModules)
245 return NULL;
246 }
247
248 /* find duplicates */
249 for (i = 0; i < _eglModules->Size; i++) {
250 mod = _eglModules->Elements[i];
251 if (strcmp(mod->Path, path) == 0)
252 return mod;
253 }
254
255 /* allocate a new one */
256 mod = calloc(1, sizeof(*mod));
257 if (mod) {
258 mod->Path = _eglstrdup(path);
259 if (!mod->Path) {
260 free(mod);
261 mod = NULL;
262 }
263 }
264 if (mod) {
265 _eglAppendArray(_eglModules, (void *) mod);
266 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
267 }
268
269 return mod;
270 }
271
272
273 /**
274 * Free a module.
275 */
276 static void
277 _eglFreeModule(void *module)
278 {
279 _EGLModule *mod = (_EGLModule *) module;
280
281 _eglUnloadModule(mod);
282 free(mod->Path);
283 free(mod);
284 }
285
286
287 /**
288 * A loader function for use with _eglPreloadForEach. The loader data is the
289 * filename of the driver. This function stops on the first valid driver.
290 */
291 static EGLBoolean
292 _eglLoaderFile(const char *dir, size_t len, void *loader_data)
293 {
294 char path[1024];
295 const char *filename = (const char *) loader_data;
296 size_t flen = strlen(filename);
297
298 /* make a full path */
299 if (len + flen + 2 > sizeof(path))
300 return EGL_TRUE;
301 if (len) {
302 memcpy(path, dir, len);
303 path[len++] = '/';
304 }
305 memcpy(path + len, filename, flen);
306 len += flen;
307 path[len] = '\0';
308
309 if (library_suffix()) {
310 const char *suffix = library_suffix();
311 size_t slen = strlen(suffix);
312 const char *p;
313 EGLBoolean need_suffix;
314
315 p = filename + flen - slen;
316 need_suffix = (p < filename || strcmp(p, suffix) != 0);
317 if (need_suffix) {
318 /* overflow */
319 if (len + slen + 1 > sizeof(path))
320 return EGL_TRUE;
321 strcpy(path + len, suffix);
322 }
323 }
324
325 #if defined(_EGL_OS_UNIX)
326 /* check if the file exists */
327 if (access(path, F_OK))
328 return EGL_TRUE;
329 #endif
330
331 _eglAddModule(path);
332
333 return EGL_TRUE;
334 }
335
336
337 /**
338 * Run the callback function on each driver directory.
339 *
340 * The process may end prematurely if the callback function returns false.
341 */
342 static void
343 _eglPreloadForEach(const char *search_path,
344 EGLBoolean (*loader)(const char *, size_t, void *),
345 void *loader_data)
346 {
347 const char *cur, *next;
348 size_t len;
349
350 cur = search_path;
351 while (cur) {
352 next = strchr(cur, ':');
353 len = (next) ? next - cur : strlen(cur);
354
355 if (!loader(cur, len, loader_data))
356 break;
357
358 cur = (next) ? next + 1 : NULL;
359 }
360 }
361
362
363 /**
364 * Return a list of colon-separated driver directories.
365 */
366 static const char *
367 _eglGetSearchPath(void)
368 {
369 static char search_path[1024];
370
371 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
372 if (search_path[0] == '\0') {
373 char *buf = search_path;
374 size_t len = sizeof(search_path);
375 EGLBoolean use_env;
376 char dir_sep;
377 int ret;
378
379 #if defined(_EGL_OS_UNIX)
380 use_env = (geteuid() == getuid() && getegid() == getgid());
381 dir_sep = '/';
382 #else
383 use_env = EGL_TRUE;
384 dir_sep = '\\';
385 #endif
386
387 if (use_env) {
388 char *p;
389
390 /* extract the dirname from EGL_DRIVER */
391 p = getenv("EGL_DRIVER");
392 if (p && strchr(p, dir_sep)) {
393 ret = _eglsnprintf(buf, len, "%s", p);
394 if (ret > 0 && ret < len) {
395 p = strrchr(buf, dir_sep);
396 *p++ = ':';
397
398 len -= p - buf;
399 buf = p;
400 }
401 }
402
403 /* append EGL_DRIVERS_PATH */
404 p = getenv("EGL_DRIVERS_PATH");
405 if (p) {
406 ret = _eglsnprintf(buf, len, "%s:", p);
407 if (ret > 0 && ret < len) {
408 buf += ret;
409 len -= ret;
410 }
411 }
412 }
413 else {
414 _eglLog(_EGL_DEBUG,
415 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
416 }
417
418 ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR);
419 if (ret < 0 || ret >= len)
420 search_path[0] = '\0';
421
422 _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path);
423 }
424 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
425
426 return search_path;
427 }
428
429
430 /**
431 * Add the user driver to the module array.
432 *
433 * The user driver is specified by EGL_DRIVER.
434 */
435 static EGLBoolean
436 _eglAddUserDriver(void)
437 {
438 const char *search_path = _eglGetSearchPath();
439 char *env;
440
441 env = getenv("EGL_DRIVER");
442 #if defined(_EGL_OS_UNIX)
443 if (env && strchr(env, '/')) {
444 search_path = "";
445 if ((geteuid() != getuid() || getegid() != getgid())) {
446 _eglLog(_EGL_DEBUG,
447 "ignore EGL_DRIVER for setuid/setgid binaries");
448 env = NULL;
449 }
450 }
451 #endif /* _EGL_OS_UNIX */
452 if (env) {
453 _EGLModule *mod;
454 EGLint i;
455
456 /* env can be a path */
457 _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
458 /* or the name of a built-in driver */
459 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
460 if (!strcmp(_eglBuiltInDrivers[i].name, env)) {
461 mod = _eglAddModule(env);
462 if (mod)
463 mod->BuiltIn = _eglBuiltInDrivers[i].main;
464 }
465 }
466
467 return EGL_TRUE;
468 }
469
470 return EGL_FALSE;
471 }
472
473
474 /**
475 * Add egl_gallium to the module array.
476 */
477 static void
478 _eglAddGalliumDriver(void)
479 {
480 #ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
481 void *external = (void *) "egl_gallium";
482 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external);
483 #endif
484 }
485
486
487 /**
488 * Add built-in drivers to the module array.
489 */
490 static void
491 _eglAddBuiltInDrivers(void)
492 {
493 _EGLModule *mod;
494 EGLint i;
495
496 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
497 mod = _eglAddModule(_eglBuiltInDrivers[i].name);
498 if (mod)
499 mod->BuiltIn = _eglBuiltInDrivers[i].main;
500 }
501 }
502
503
504 /**
505 * Add drivers to the module array. Drivers will be loaded as they are matched
506 * to displays.
507 */
508 static EGLBoolean
509 _eglAddDrivers(void)
510 {
511 if (_eglModules)
512 return EGL_TRUE;
513
514 if (!_eglAddUserDriver()) {
515 /*
516 * Add other drivers only when EGL_DRIVER is not set. The order here
517 * decides the priorities.
518 */
519 _eglAddGalliumDriver();
520 _eglAddBuiltInDrivers();
521 }
522
523 return (_eglModules != NULL);
524 }
525
526
527 /**
528 * Match a display to a driver. The display is initialized unless use_probe is
529 * true.
530 *
531 * The matching is done by finding the first driver that can initialize the
532 * display, or when use_probe is true, the driver with highest score.
533 */
534 _EGLDriver *
535 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean use_probe)
536 {
537 _EGLModule *mod;
538 _EGLDriver *best_drv = NULL;
539 EGLint best_score = 0;
540 EGLint major, minor, i;
541
542 _eglLockMutex(&_eglModuleMutex);
543
544 if (!_eglAddDrivers()) {
545 _eglUnlockMutex(&_eglModuleMutex);
546 _eglLog(_EGL_WARNING, "failed to find any driver");
547 return EGL_FALSE;
548 }
549
550 /* match the loaded modules */
551 for (i = 0; i < _eglModules->Size; i++) {
552 mod = (_EGLModule *) _eglModules->Elements[i];
553 if (!mod->Driver)
554 break;
555
556 if (use_probe) {
557 EGLint score = (mod->Driver->Probe) ?
558 mod->Driver->Probe(mod->Driver, dpy) : 1;
559 if (score > best_score) {
560 best_drv = mod->Driver;
561 best_score = score;
562 }
563 }
564 else {
565 if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor)) {
566 best_drv = mod->Driver;
567 best_score = 100;
568 }
569 }
570 /* perfect match */
571 if (best_score >= 100)
572 break;
573 }
574
575 /* load more modules */
576 if (!best_drv) {
577 EGLint first_unloaded = i;
578
579 while (i < _eglModules->Size) {
580 mod = (_EGLModule *) _eglModules->Elements[i];
581 assert(!mod->Driver);
582
583 if (!_eglLoadModule(mod)) {
584 /* remove invalid modules */
585 _eglEraseArray(_eglModules, i, _eglFreeModule);
586 continue;
587 }
588
589 if (use_probe) {
590 best_score = (mod->Driver->Probe) ?
591 mod->Driver->Probe(mod->Driver, dpy) : 1;
592 }
593 else {
594 if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor))
595 best_score = 100;
596 }
597
598 if (best_score > 0) {
599 best_drv = mod->Driver;
600 /* loaded modules come before unloaded ones */
601 if (first_unloaded != i) {
602 void *tmp = _eglModules->Elements[i];
603 _eglModules->Elements[i] =
604 _eglModules->Elements[first_unloaded];
605 _eglModules->Elements[first_unloaded] = tmp;
606 }
607 break;
608 }
609 else {
610 _eglUnloadModule(mod);
611 i++;
612 }
613 }
614 }
615
616 _eglUnlockMutex(&_eglModuleMutex);
617
618 if (best_drv) {
619 _eglLog(_EGL_DEBUG, "the best driver is %s (score %d)",
620 best_drv->Name, best_score);
621 if (!use_probe) {
622 dpy->Driver = best_drv;
623 dpy->Initialized = EGL_TRUE;
624 dpy->APImajor = major;
625 dpy->APIminor = minor;
626 }
627 }
628
629 return best_drv;
630 }
631
632
633 __eglMustCastToProperFunctionPointerType
634 _eglGetDriverProc(const char *procname)
635 {
636 EGLint i;
637 _EGLProc proc = NULL;
638
639 if (!_eglModules) {
640 /* load the driver for the default display */
641 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
642 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
643 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
644 return NULL;
645 }
646
647 for (i = 0; i < _eglModules->Size; i++) {
648 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
649
650 if (!mod->Driver)
651 break;
652 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
653 if (proc)
654 break;
655 }
656
657 return proc;
658 }
659
660
661 /**
662 * Unload all drivers.
663 */
664 void
665 _eglUnloadDrivers(void)
666 {
667 /* this is called at atexit time */
668 if (_eglModules) {
669 _eglDestroyArray(_eglModules, _eglFreeModule);
670 _eglModules = NULL;
671 }
672 }
673
674
675 /**
676 * Invoke a callback function on each EGL search path.
677 *
678 * The first argument of the callback function is the name of the search path.
679 * The second argument is the length of the name.
680 */
681 void
682 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
683 void *callback_data)
684 {
685 const char *search_path = _eglGetSearchPath();
686 _eglPreloadForEach(search_path, callback, callback_data);
687 }