Merge remote branch 'vdpau/pipe-video' 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 #if defined(_EGL_OS_UNIX)
190 /* destroy the driver */
191 if (mod->Driver && mod->Driver->Unload)
192 mod->Driver->Unload(mod->Driver);
193
194 /*
195 * XXX At this point (atexit), the module might be the last reference to
196 * libEGL. Closing the module might unmap libEGL and give problems.
197 */
198 #if 0
199 if (mod->Handle)
200 close_library(mod->Handle);
201 #endif
202 #elif defined(_EGL_OS_WINDOWS)
203 /* XXX Windows unloads DLLs before atexit */
204 #endif
205
206 mod->Driver = NULL;
207 mod->Handle = NULL;
208 }
209
210
211 /**
212 * Add a module to the module array.
213 */
214 static _EGLModule *
215 _eglAddModule(const char *path)
216 {
217 _EGLModule *mod;
218 EGLint i;
219
220 if (!_eglModules) {
221 _eglModules = _eglCreateArray("Module", 8);
222 if (!_eglModules)
223 return NULL;
224 }
225
226 /* find duplicates */
227 for (i = 0; i < _eglModules->Size; i++) {
228 mod = _eglModules->Elements[i];
229 if (strcmp(mod->Path, path) == 0)
230 return mod;
231 }
232
233 /* allocate a new one */
234 mod = calloc(1, sizeof(*mod));
235 if (mod) {
236 mod->Path = _eglstrdup(path);
237 if (!mod->Path) {
238 free(mod);
239 mod = NULL;
240 }
241 }
242 if (mod) {
243 _eglAppendArray(_eglModules, (void *) mod);
244 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
245 }
246
247 return mod;
248 }
249
250
251 /**
252 * Free a module.
253 */
254 static void
255 _eglFreeModule(void *module)
256 {
257 _EGLModule *mod = (_EGLModule *) module;
258
259 _eglUnloadModule(mod);
260 free(mod->Path);
261 free(mod);
262 }
263
264
265 /**
266 * A loader function for use with _eglPreloadForEach. The loader data is the
267 * filename of the driver. This function stops on the first valid driver.
268 */
269 static EGLBoolean
270 _eglLoaderFile(const char *dir, size_t len, void *loader_data)
271 {
272 char path[1024];
273 const char *filename = (const char *) loader_data;
274 size_t flen = strlen(filename);
275
276 /* make a full path */
277 if (len + flen + 2 > sizeof(path))
278 return EGL_TRUE;
279 if (len) {
280 memcpy(path, dir, len);
281 path[len++] = '/';
282 }
283 memcpy(path + len, filename, flen);
284 len += flen;
285 path[len] = '\0';
286
287 if (library_suffix()) {
288 const char *suffix = library_suffix();
289 size_t slen = strlen(suffix);
290 const char *p;
291 EGLBoolean need_suffix;
292
293 p = filename + flen - slen;
294 need_suffix = (p < filename || strcmp(p, suffix) != 0);
295 if (need_suffix) {
296 /* overflow */
297 if (len + slen + 1 > sizeof(path))
298 return EGL_TRUE;
299 strcpy(path + len, suffix);
300 }
301 }
302
303 #if defined(_EGL_OS_UNIX)
304 /* check if the file exists */
305 if (access(path, F_OK))
306 return EGL_TRUE;
307 #endif
308
309 _eglAddModule(path);
310
311 return EGL_TRUE;
312 }
313
314
315 /**
316 * A loader function for use with _eglPreloadForEach. The loader data is the
317 * pattern (prefix) of the files to look for.
318 */
319 static EGLBoolean
320 _eglLoaderPattern(const char *dir, size_t len, void *loader_data)
321 {
322 #if defined(_EGL_OS_UNIX)
323 const char *prefix, *suffix;
324 size_t prefix_len, suffix_len;
325 DIR *dirp;
326 struct dirent *dirent;
327 char path[1024];
328
329 if (len + 2 > sizeof(path))
330 return EGL_TRUE;
331 if (len) {
332 memcpy(path, dir, len);
333 path[len++] = '/';
334 }
335 path[len] = '\0';
336
337 dirp = opendir(path);
338 if (!dirp)
339 return EGL_TRUE;
340
341 prefix = (const char *) loader_data;
342 prefix_len = strlen(prefix);
343 suffix = library_suffix();
344 suffix_len = (suffix) ? strlen(suffix) : 0;
345
346 while ((dirent = readdir(dirp))) {
347 size_t dirent_len = strlen(dirent->d_name);
348 const char *p;
349
350 /* match the prefix */
351 if (strncmp(dirent->d_name, prefix, prefix_len) != 0)
352 continue;
353 /* match the suffix */
354 if (suffix) {
355 p = dirent->d_name + dirent_len - suffix_len;
356 if (p < dirent->d_name || strcmp(p, suffix) != 0)
357 continue;
358 }
359
360 /* make a full path and add it to the module array */
361 if (len + dirent_len + 1 <= sizeof(path)) {
362 strcpy(path + len, dirent->d_name);
363 _eglAddModule(path);
364 }
365 }
366
367 closedir(dirp);
368
369 return EGL_TRUE;
370 #else /* _EGL_OS_UNIX */
371 /* stop immediately */
372 return EGL_FALSE;
373 #endif
374 }
375
376
377 /**
378 * Run the callback function on each driver directory.
379 *
380 * The process may end prematurely if the callback function returns false.
381 */
382 static void
383 _eglPreloadForEach(const char *search_path,
384 EGLBoolean (*loader)(const char *, size_t, void *),
385 void *loader_data)
386 {
387 const char *cur, *next;
388 size_t len;
389
390 cur = search_path;
391 while (cur) {
392 next = strchr(cur, ':');
393 len = (next) ? next - cur : strlen(cur);
394
395 if (!loader(cur, len, loader_data))
396 break;
397
398 cur = (next) ? next + 1 : NULL;
399 }
400 }
401
402
403 /**
404 * Return a list of colon-separated driver directories.
405 */
406 static const char *
407 _eglGetSearchPath(void)
408 {
409 static char search_path[1024];
410
411 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
412 if (search_path[0] == '\0') {
413 char *buf = search_path;
414 size_t len = sizeof(search_path);
415 EGLBoolean use_env;
416 char dir_sep;
417 int ret;
418
419 #if defined(_EGL_OS_UNIX)
420 use_env = (geteuid() == getuid() && getegid() == getgid());
421 dir_sep = '/';
422 #else
423 use_env = EGL_TRUE;
424 dir_sep = '\\';
425 #endif
426
427 if (use_env) {
428 char *p;
429
430 /* extract the dirname from EGL_DRIVER */
431 p = getenv("EGL_DRIVER");
432 if (p && strchr(p, dir_sep)) {
433 ret = _eglsnprintf(buf, len, "%s", p);
434 if (ret > 0 && ret < len) {
435 p = strrchr(buf, dir_sep);
436 *p++ = ':';
437
438 len -= p - buf;
439 buf = p;
440 }
441 }
442
443 /* append EGL_DRIVERS_PATH */
444 p = getenv("EGL_DRIVERS_PATH");
445 if (p) {
446 ret = _eglsnprintf(buf, len, "%s:", p);
447 if (ret > 0 && ret < len) {
448 buf += ret;
449 len -= ret;
450 }
451 }
452 }
453 else {
454 _eglLog(_EGL_DEBUG,
455 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
456 }
457
458 ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR);
459 if (ret < 0 || ret >= len)
460 search_path[0] = '\0';
461
462 _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path);
463 }
464 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
465
466 return search_path;
467 }
468
469
470 /**
471 * Add the user driver to the module array.
472 *
473 * The user driver is specified by EGL_DRIVER.
474 */
475 static void
476 _eglAddUserDriver(void)
477 {
478 const char *search_path = _eglGetSearchPath();
479 char *env;
480
481 env = getenv("EGL_DRIVER");
482 #if defined(_EGL_OS_UNIX)
483 if (env && strchr(env, '/')) {
484 search_path = "";
485 if ((geteuid() != getuid() || getegid() != getgid())) {
486 _eglLog(_EGL_DEBUG,
487 "ignore EGL_DRIVER for setuid/setgid binaries");
488 env = NULL;
489 }
490 }
491 #endif /* _EGL_OS_UNIX */
492 if (env)
493 _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
494 }
495
496
497 /**
498 * Add default drivers to the module array.
499 */
500 static void
501 _eglAddDefaultDrivers(void)
502 {
503 const char *search_path = _eglGetSearchPath();
504 EGLint i;
505 #if defined(_EGL_OS_WINDOWS)
506 const char *DefaultDriverNames[] = {
507 "egl_gallium"
508 };
509 #elif defined(_EGL_OS_UNIX)
510 const char *DefaultDriverNames[] = {
511 "egl_gallium",
512 "egl_dri2",
513 "egl_glx"
514 };
515 #endif
516
517 for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
518 void *name = (void *) DefaultDriverNames[i];
519 _eglPreloadForEach(search_path, _eglLoaderFile, name);
520 }
521 }
522
523
524 /**
525 * Add drivers to the module array. Drivers will be loaded as they are matched
526 * to displays.
527 */
528 static EGLBoolean
529 _eglAddDrivers(void)
530 {
531 if (_eglModules)
532 return EGL_TRUE;
533
534 /* the order here decides the priorities of the drivers */
535 _eglAddUserDriver();
536 _eglAddDefaultDrivers();
537 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderPattern, (void *) "egl_");
538
539 return (_eglModules != NULL);
540 }
541
542
543 /**
544 * Match a display to a driver. The display is initialized unless use_probe is
545 * true.
546 *
547 * The matching is done by finding the first driver that can initialize the
548 * display, or when use_probe is true, the driver with highest score.
549 */
550 _EGLDriver *
551 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean use_probe)
552 {
553 _EGLModule *mod;
554 _EGLDriver *best_drv = NULL;
555 EGLint best_score = 0;
556 EGLint major, minor, i;
557
558 _eglLockMutex(&_eglModuleMutex);
559
560 if (!_eglAddDrivers()) {
561 _eglUnlockMutex(&_eglModuleMutex);
562 return EGL_FALSE;
563 }
564
565 /* match the loaded modules */
566 for (i = 0; i < _eglModules->Size; i++) {
567 mod = (_EGLModule *) _eglModules->Elements[i];
568 if (!mod->Driver)
569 break;
570
571 if (use_probe) {
572 EGLint score = (mod->Driver->Probe) ?
573 mod->Driver->Probe(mod->Driver, dpy) : 1;
574 if (score > best_score) {
575 best_drv = mod->Driver;
576 best_score = score;
577 }
578 }
579 else {
580 if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor)) {
581 best_drv = mod->Driver;
582 best_score = 100;
583 }
584 }
585 /* perfect match */
586 if (best_score >= 100)
587 break;
588 }
589
590 /* load more modules */
591 if (!best_drv) {
592 EGLint first_unloaded = i;
593
594 while (i < _eglModules->Size) {
595 mod = (_EGLModule *) _eglModules->Elements[i];
596 assert(!mod->Driver);
597
598 if (!_eglLoadModule(mod)) {
599 /* remove invalid modules */
600 _eglEraseArray(_eglModules, i, _eglFreeModule);
601 continue;
602 }
603
604 if (use_probe) {
605 best_score = (mod->Driver->Probe) ?
606 mod->Driver->Probe(mod->Driver, dpy) : 1;
607 }
608 else {
609 if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor))
610 best_score = 100;
611 }
612
613 if (best_score > 0) {
614 best_drv = mod->Driver;
615 /* loaded modules come before unloaded ones */
616 if (first_unloaded != i) {
617 void *tmp = _eglModules->Elements[i];
618 _eglModules->Elements[i] =
619 _eglModules->Elements[first_unloaded];
620 _eglModules->Elements[first_unloaded] = tmp;
621 }
622 break;
623 }
624 else {
625 _eglUnloadModule(mod);
626 i++;
627 }
628 }
629 }
630
631 _eglUnlockMutex(&_eglModuleMutex);
632
633 if (best_drv) {
634 _eglLog(_EGL_DEBUG, "the best driver is %s (score %d)",
635 best_drv->Name, best_score);
636 if (!use_probe) {
637 dpy->Driver = best_drv;
638 dpy->Initialized = EGL_TRUE;
639 dpy->APImajor = major;
640 dpy->APIminor = minor;
641 }
642 }
643
644 return best_drv;
645 }
646
647
648 __eglMustCastToProperFunctionPointerType
649 _eglGetDriverProc(const char *procname)
650 {
651 EGLint i;
652 _EGLProc proc = NULL;
653
654 if (!_eglModules) {
655 /* load the driver for the default display */
656 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
657 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
658 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
659 return NULL;
660 }
661
662 for (i = 0; i < _eglModules->Size; i++) {
663 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
664
665 if (!mod->Driver)
666 break;
667 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
668 if (proc)
669 break;
670 }
671
672 return proc;
673 }
674
675
676 /**
677 * Unload all drivers.
678 */
679 void
680 _eglUnloadDrivers(void)
681 {
682 /* this is called at atexit time */
683 if (_eglModules) {
684 _eglDestroyArray(_eglModules, _eglFreeModule);
685 _eglModules = NULL;
686 }
687 }
688
689
690 /**
691 * Invoke a callback function on each EGL search path.
692 *
693 * The first argument of the callback function is the name of the search path.
694 * The second argument is the length of the name.
695 */
696 void
697 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
698 void *callback_data)
699 {
700 const char *search_path = _eglGetSearchPath();
701 _eglPreloadForEach(search_path, callback, callback_data);
702 }