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
{
33 static _EGL_DECLARE_MUTEX(_eglModuleMutex
);
34 static _EGLArray
*_eglModules
;
39 } _eglBuiltInDrivers
[] = {
40 #ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
41 { "egl_gallium", _eglBuiltInDriverGALLIUM
},
43 #ifdef _EGL_BUILT_IN_DRIVER_DRI2
44 { "egl_dri2", _eglBuiltInDriverDRI2
},
46 #ifdef _EGL_BUILT_IN_DRIVER_GLX
47 { "egl_glx", _eglBuiltInDriverGLX
},
53 * Wrappers for dlopen/dlclose()
55 #if defined(_EGL_OS_WINDOWS)
58 typedef HMODULE lib_handle
;
61 open_library(const char *filename
)
63 return LoadLibrary(filename
);
67 close_library(HMODULE lib
)
80 #elif defined(_EGL_OS_UNIX)
83 typedef void * lib_handle
;
86 open_library(const char *filename
)
88 return dlopen(filename
, RTLD_LAZY
);
92 close_library(void *lib
)
109 * Open the named driver and find its bootstrap function: _eglMain().
112 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
115 _EGLMain_t mainFunc
= NULL
;
116 const char *error
= "unknown error";
120 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
121 lib
= open_library(driverPath
);
123 #if defined(_EGL_OS_WINDOWS)
126 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
127 #elif defined(_EGL_OS_UNIX)
133 /* direct cast gives a warning when compiled with -pedantic */
134 tmp
.ptr
= dlsym(lib
, "_eglMain");
145 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
151 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
164 * Load a module and create the driver object.
167 _eglLoadModule(_EGLModule
*mod
)
177 lib
= (lib_handle
) NULL
;
178 mainFunc
= mod
->BuiltIn
;
181 mainFunc
= _eglOpenLibrary(mod
->Path
, &lib
);
186 drv
= mainFunc(NULL
);
194 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", mod
->Path
);
195 drv
->Name
= "UNNAMED";
198 mod
->Handle
= (void *) lib
;
209 _eglUnloadModule(_EGLModule
*mod
)
211 #if defined(_EGL_OS_UNIX)
212 /* destroy the driver */
213 if (mod
->Driver
&& mod
->Driver
->Unload
)
214 mod
->Driver
->Unload(mod
->Driver
);
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.
222 close_library(mod
->Handle
);
224 #elif defined(_EGL_OS_WINDOWS)
225 /* XXX Windows unloads DLLs before atexit */
234 * Add a module to the module array.
237 _eglAddModule(const char *path
)
243 _eglModules
= _eglCreateArray("Module", 8);
248 /* find duplicates */
249 for (i
= 0; i
< _eglModules
->Size
; i
++) {
250 mod
= _eglModules
->Elements
[i
];
251 if (strcmp(mod
->Path
, path
) == 0)
255 /* allocate a new one */
256 mod
= calloc(1, sizeof(*mod
));
258 mod
->Path
= _eglstrdup(path
);
265 _eglAppendArray(_eglModules
, (void *) mod
);
266 _eglLog(_EGL_DEBUG
, "added %s to module array", mod
->Path
);
277 _eglFreeModule(void *module
)
279 _EGLModule
*mod
= (_EGLModule
*) module
;
281 _eglUnloadModule(mod
);
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.
292 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
295 const char *filename
= (const char *) loader_data
;
296 size_t flen
= strlen(filename
);
298 /* make a full path */
299 if (len
+ flen
+ 2 > sizeof(path
))
302 memcpy(path
, dir
, len
);
305 memcpy(path
+ len
, filename
, flen
);
309 if (library_suffix()) {
310 const char *suffix
= library_suffix();
311 size_t slen
= strlen(suffix
);
313 EGLBoolean need_suffix
;
315 p
= filename
+ flen
- slen
;
316 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
319 if (len
+ slen
+ 1 > sizeof(path
))
321 strcpy(path
+ len
, suffix
);
325 #if defined(_EGL_OS_UNIX)
326 /* check if the file exists */
327 if (access(path
, F_OK
))
338 * Run the callback function on each driver directory.
340 * The process may end prematurely if the callback function returns false.
343 _eglPreloadForEach(const char *search_path
,
344 EGLBoolean (*loader
)(const char *, size_t, void *),
347 const char *cur
, *next
;
352 next
= strchr(cur
, ':');
353 len
= (next
) ? next
- cur
: strlen(cur
);
355 if (!loader(cur
, len
, loader_data
))
358 cur
= (next
) ? next
+ 1 : NULL
;
364 * Return a list of colon-separated driver directories.
367 _eglGetSearchPath(void)
369 static char search_path
[1024];
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
);
379 #if defined(_EGL_OS_UNIX)
380 use_env
= (geteuid() == getuid() && getegid() == getgid());
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
);
403 /* append EGL_DRIVERS_PATH */
404 p
= getenv("EGL_DRIVERS_PATH");
406 ret
= _eglsnprintf(buf
, len
, "%s:", p
);
407 if (ret
> 0 && ret
< len
) {
415 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
418 ret
= _eglsnprintf(buf
, len
, "%s", _EGL_DRIVER_SEARCH_DIR
);
419 if (ret
< 0 || ret
>= len
)
420 search_path
[0] = '\0';
422 _eglLog(_EGL_DEBUG
, "EGL search path is %s", search_path
);
424 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
431 * Add the user driver to the module array.
433 * The user driver is specified by EGL_DRIVER.
436 _eglAddUserDriver(void)
438 const char *search_path
= _eglGetSearchPath();
442 env
= getenv("EGL_DRIVER");
443 #if defined(_EGL_OS_UNIX)
444 if (env
&& strchr(env
, '/')) {
446 if ((geteuid() != getuid() || getegid() != getgid())) {
448 "ignore EGL_DRIVER for setuid/setgid binaries");
453 char *suffix
= strchr(env
, '.');
454 name_len
= (suffix
) ? suffix
- env
: strlen(env
);
458 name_len
= strlen(env
);
459 #endif /* _EGL_OS_UNIX */
462 * Try built-in drivers first if we know the driver name. This makes sure
463 * we do not load the outdated external driver that is still on the
470 for (i
= 0; _eglBuiltInDrivers
[i
].name
; i
++) {
471 if (strlen(_eglBuiltInDrivers
[i
].name
) == name_len
&&
472 !strncmp(_eglBuiltInDrivers
[i
].name
, env
, name_len
)) {
473 mod
= _eglAddModule(env
);
475 mod
->BuiltIn
= _eglBuiltInDrivers
[i
].main
;
482 /* otherwise, treat env as a path */
484 _eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
);
494 * Add egl_gallium to the module array.
497 _eglAddGalliumDriver(void)
499 #ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
500 void *external
= (void *) "egl_gallium";
501 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile
, external
);
507 * Add built-in drivers to the module array.
510 _eglAddBuiltInDrivers(void)
515 for (i
= 0; _eglBuiltInDrivers
[i
].name
; i
++) {
516 mod
= _eglAddModule(_eglBuiltInDrivers
[i
].name
);
518 mod
->BuiltIn
= _eglBuiltInDrivers
[i
].main
;
524 * Add drivers to the module array. Drivers will be loaded as they are matched
533 if (!_eglAddUserDriver()) {
535 * Add other drivers only when EGL_DRIVER is not set. The order here
536 * decides the priorities.
538 _eglAddGalliumDriver();
539 _eglAddBuiltInDrivers();
542 return (_eglModules
!= NULL
);
547 * A helper function for _eglMatchDriver. It finds the first driver that can
548 * initialize the display and return.
551 _eglMatchAndInitialize(_EGLDisplay
*dpy
)
553 _EGLDriver
*drv
= NULL
;
556 if (!_eglAddDrivers()) {
557 _eglLog(_EGL_WARNING
, "failed to find any driver");
563 /* no re-matching? */
564 if (!drv
->API
.Initialize(drv
, dpy
))
569 while (i
< _eglModules
->Size
) {
570 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
572 if (!_eglLoadModule(mod
)) {
573 /* remove invalid modules */
574 _eglEraseArray(_eglModules
, i
, _eglFreeModule
);
578 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
)) {
592 * Match a display to a driver. The display is initialized unless test_only is
593 * true. The matching is done by finding the first driver that can initialize
597 _eglMatchDriver(_EGLDisplay
*dpy
, EGLBoolean test_only
)
599 _EGLDriver
*best_drv
;
601 assert(!dpy
->Initialized
);
603 _eglLockMutex(&_eglModuleMutex
);
606 dpy
->Options
.TestOnly
= test_only
;
607 dpy
->Options
.UseFallback
= EGL_FALSE
;
609 best_drv
= _eglMatchAndInitialize(dpy
);
611 dpy
->Options
.UseFallback
= EGL_TRUE
;
612 best_drv
= _eglMatchAndInitialize(dpy
);
615 _eglUnlockMutex(&_eglModuleMutex
);
618 _eglLog(_EGL_DEBUG
, "the best driver is %s%s",
619 best_drv
->Name
, (test_only
) ? " (test only) " : "");
621 dpy
->Driver
= best_drv
;
622 dpy
->Initialized
= EGL_TRUE
;
630 __eglMustCastToProperFunctionPointerType
631 _eglGetDriverProc(const char *procname
)
634 _EGLProc proc
= NULL
;
637 /* load the driver for the default display */
638 EGLDisplay egldpy
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
639 _EGLDisplay
*dpy
= _eglLookupDisplay(egldpy
);
640 if (!dpy
|| !_eglMatchDriver(dpy
, EGL_TRUE
))
644 for (i
= 0; i
< _eglModules
->Size
; i
++) {
645 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
649 proc
= mod
->Driver
->API
.GetProcAddress(mod
->Driver
, procname
);
659 * Unload all drivers.
662 _eglUnloadDrivers(void)
664 /* this is called at atexit time */
666 _eglDestroyArray(_eglModules
, _eglFreeModule
);
673 * Invoke a callback function on each EGL search path.
675 * The first argument of the callback function is the name of the search path.
676 * The second argument is the length of the name.
679 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
682 const char *search_path
= _eglGetSearchPath();
683 _eglPreloadForEach(search_path
, callback
, callback_data
);