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