2 * Functions for choosing and opening/loading device drivers.
11 #include "eglstring.h"
12 #include "egldefines.h"
13 #include "egldisplay.h"
14 #include "egldriver.h"
18 #if defined(_EGL_OS_UNIX)
20 #include <sys/types.h>
26 typedef struct _egl_module
{
32 static _EGL_DECLARE_MUTEX(_eglModuleMutex
);
33 static _EGLArray
*_eglModules
;
37 * Wrappers for dlopen/dlclose()
39 #if defined(_EGL_OS_WINDOWS)
42 typedef HMODULE lib_handle
;
45 open_library(const char *filename
)
47 return LoadLibrary(filename
);
51 close_library(HMODULE lib
)
64 #elif defined(_EGL_OS_UNIX)
67 typedef void * lib_handle
;
70 open_library(const char *filename
)
72 return dlopen(filename
, RTLD_LAZY
);
76 close_library(void *lib
)
93 * Open the named driver and find its bootstrap function: _eglMain().
96 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
99 _EGLMain_t mainFunc
= NULL
;
100 const char *error
= "unknown error";
104 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
105 lib
= open_library(driverPath
);
107 #if defined(_EGL_OS_WINDOWS)
110 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
111 #elif defined(_EGL_OS_UNIX)
117 /* direct cast gives a warning when compiled with -pedantic */
118 tmp
.ptr
= dlsym(lib
, "_eglMain");
129 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
131 if (!getenv("EGL_DRIVER"))
132 _eglLog(_EGL_WARNING
,
133 "The driver can be overridden by setting EGL_DRIVER");
138 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
151 * Load a module and create the driver object.
154 _eglLoadModule(_EGLModule
*mod
)
160 mainFunc
= _eglOpenLibrary(mod
->Path
, &lib
);
164 drv
= mainFunc(NULL
);
172 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", mod
->Path
);
173 drv
->Name
= "UNNAMED";
176 mod
->Handle
= (void *) lib
;
187 _eglUnloadModule(_EGLModule
*mod
)
189 #if defined(_EGL_OS_UNIX)
190 /* destroy the driver */
191 if (mod
->Driver
&& mod
->Driver
->Unload
)
192 mod
->Driver
->Unload(mod
->Driver
);
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.
200 close_library(mod
->Handle
);
202 #elif defined(_EGL_OS_WINDOWS)
203 /* XXX Windows unloads DLLs before atexit */
212 * Add a module to the module array.
215 _eglAddModule(const char *path
)
221 _eglModules
= _eglCreateArray("Module", 8);
226 /* find duplicates */
227 for (i
= 0; i
< _eglModules
->Size
; i
++) {
228 mod
= _eglModules
->Elements
[i
];
229 if (strcmp(mod
->Path
, path
) == 0)
233 /* allocate a new one */
234 mod
= calloc(1, sizeof(*mod
));
236 mod
->Path
= _eglstrdup(path
);
243 _eglAppendArray(_eglModules
, (void *) mod
);
244 _eglLog(_EGL_DEBUG
, "added %s to module array", mod
->Path
);
255 _eglFreeModule(void *module
)
257 _EGLModule
*mod
= (_EGLModule
*) module
;
259 _eglUnloadModule(mod
);
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.
270 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
273 const char *filename
= (const char *) loader_data
;
274 size_t flen
= strlen(filename
);
276 /* make a full path */
277 if (len
+ flen
+ 2 > sizeof(path
))
280 memcpy(path
, dir
, len
);
283 memcpy(path
+ len
, filename
, flen
);
287 if (library_suffix()) {
288 const char *suffix
= library_suffix();
289 size_t slen
= strlen(suffix
);
291 EGLBoolean need_suffix
;
293 p
= filename
+ flen
- slen
;
294 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
297 if (len
+ slen
+ 1 > sizeof(path
))
299 strcpy(path
+ len
, suffix
);
303 #if defined(_EGL_OS_UNIX)
304 /* check if the file exists */
305 if (access(path
, F_OK
))
316 * A loader function for use with _eglPreloadForEach. The loader data is the
317 * pattern (prefix) of the files to look for.
320 _eglLoaderPattern(const char *dir
, size_t len
, void *loader_data
)
322 #if defined(_EGL_OS_UNIX)
323 const char *prefix
, *suffix
;
324 size_t prefix_len
, suffix_len
;
326 struct dirent
*dirent
;
329 if (len
+ 2 > sizeof(path
))
332 memcpy(path
, dir
, len
);
337 dirp
= opendir(path
);
341 prefix
= (const char *) loader_data
;
342 prefix_len
= strlen(prefix
);
343 suffix
= library_suffix();
344 suffix_len
= (suffix
) ? strlen(suffix
) : 0;
346 while ((dirent
= readdir(dirp
))) {
347 size_t dirent_len
= strlen(dirent
->d_name
);
350 /* match the prefix */
351 if (strncmp(dirent
->d_name
, prefix
, prefix_len
) != 0)
353 /* match the suffix */
355 p
= dirent
->d_name
+ dirent_len
- suffix_len
;
356 if (p
< dirent
->d_name
|| strcmp(p
, suffix
) != 0)
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
);
370 #else /* _EGL_OS_UNIX */
371 /* stop immediately */
378 * Run the callback function on each driver directory.
380 * The process may end prematurely if the callback function returns false.
383 _eglPreloadForEach(const char *search_path
,
384 EGLBoolean (*loader
)(const char *, size_t, void *),
387 const char *cur
, *next
;
392 next
= strchr(cur
, ':');
393 len
= (next
) ? next
- cur
: strlen(cur
);
395 if (!loader(cur
, len
, loader_data
))
398 cur
= (next
) ? next
+ 1 : NULL
;
404 * Return a list of colon-separated driver directories.
407 _eglGetSearchPath(void)
409 static char search_path
[1024];
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
);
419 #if defined(_EGL_OS_UNIX)
420 use_env
= (geteuid() == getuid() && getegid() == getgid());
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
);
443 /* append EGL_DRIVERS_PATH */
444 p
= getenv("EGL_DRIVERS_PATH");
446 ret
= _eglsnprintf(buf
, len
, "%s:", p
);
447 if (ret
> 0 && ret
< len
) {
455 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
458 ret
= _eglsnprintf(buf
, len
, "%s", _EGL_DRIVER_SEARCH_DIR
);
459 if (ret
< 0 || ret
>= len
)
460 search_path
[0] = '\0';
462 _eglLog(_EGL_DEBUG
, "EGL search path is %s", search_path
);
464 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
471 * Add the user driver to the module array.
473 * The user driver is specified by EGL_DRIVER.
476 _eglAddUserDriver(void)
478 const char *search_path
= _eglGetSearchPath();
481 env
= getenv("EGL_DRIVER");
482 #if defined(_EGL_OS_UNIX)
483 if (env
&& strchr(env
, '/')) {
485 if ((geteuid() != getuid() || getegid() != getgid())) {
487 "ignore EGL_DRIVER for setuid/setgid binaries");
491 #endif /* _EGL_OS_UNIX */
493 _eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
);
498 * Add default drivers to the module array.
501 _eglAddDefaultDrivers(void)
503 const char *search_path
= _eglGetSearchPath();
505 #if defined(_EGL_OS_WINDOWS)
506 const char *DefaultDriverNames
[] = {
509 #elif defined(_EGL_OS_UNIX)
510 const char *DefaultDriverNames
[] = {
517 for (i
= 0; i
< ARRAY_SIZE(DefaultDriverNames
); i
++) {
518 void *name
= (void *) DefaultDriverNames
[i
];
519 _eglPreloadForEach(search_path
, _eglLoaderFile
, name
);
525 * Add drivers to the module array. Drivers will be loaded as they are matched
534 /* the order here decides the priorities of the drivers */
536 _eglAddDefaultDrivers();
537 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderPattern
, (void *) "egl_");
539 return (_eglModules
!= NULL
);
544 * Match a display to a driver. The display is initialized unless use_probe is
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.
551 _eglMatchDriver(_EGLDisplay
*dpy
, EGLBoolean use_probe
)
554 _EGLDriver
*best_drv
= NULL
;
555 EGLint best_score
= 0;
556 EGLint major
, minor
, i
;
558 _eglLockMutex(&_eglModuleMutex
);
560 if (!_eglAddDrivers()) {
561 _eglUnlockMutex(&_eglModuleMutex
);
565 /* match the loaded modules */
566 for (i
= 0; i
< _eglModules
->Size
; i
++) {
567 mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
572 EGLint score
= (mod
->Driver
->Probe
) ?
573 mod
->Driver
->Probe(mod
->Driver
, dpy
) : 1;
574 if (score
> best_score
) {
575 best_drv
= mod
->Driver
;
580 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
, &major
, &minor
)) {
581 best_drv
= mod
->Driver
;
586 if (best_score
>= 100)
590 /* load more modules */
592 EGLint first_unloaded
= i
;
594 while (i
< _eglModules
->Size
) {
595 mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
596 assert(!mod
->Driver
);
598 if (!_eglLoadModule(mod
)) {
599 /* remove invalid modules */
600 _eglEraseArray(_eglModules
, i
, _eglFreeModule
);
605 best_score
= (mod
->Driver
->Probe
) ?
606 mod
->Driver
->Probe(mod
->Driver
, dpy
) : 1;
609 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
, &major
, &minor
))
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
;
625 _eglUnloadModule(mod
);
631 _eglUnlockMutex(&_eglModuleMutex
);
634 _eglLog(_EGL_DEBUG
, "the best driver is %s (score %d)",
635 best_drv
->Name
, best_score
);
637 dpy
->Driver
= best_drv
;
638 dpy
->Initialized
= EGL_TRUE
;
639 dpy
->APImajor
= major
;
640 dpy
->APIminor
= minor
;
648 __eglMustCastToProperFunctionPointerType
649 _eglGetDriverProc(const char *procname
)
652 _EGLProc proc
= NULL
;
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
))
662 for (i
= 0; i
< _eglModules
->Size
; i
++) {
663 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
667 proc
= mod
->Driver
->API
.GetProcAddress(mod
->Driver
, procname
);
677 * Unload all drivers.
680 _eglUnloadDrivers(void)
682 /* this is called at atexit time */
684 _eglDestroyArray(_eglModules
, _eglFreeModule
);
691 * Invoke a callback function on each EGL search path.
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.
697 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
700 const char *search_path
= _eglGetSearchPath();
701 _eglPreloadForEach(search_path
, callback
, callback_data
);