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