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_DRI2
41 { "egl_dri2", _eglBuiltInDriverDRI2
},
43 #ifdef _EGL_BUILT_IN_DRIVER_GLX
44 { "egl_glx", _eglBuiltInDriverGLX
},
50 * Wrappers for dlopen/dlclose()
52 #if defined(_EGL_OS_WINDOWS)
55 typedef HMODULE lib_handle
;
58 open_library(const char *filename
)
60 return LoadLibrary(filename
);
64 close_library(HMODULE lib
)
77 #elif defined(_EGL_OS_UNIX)
80 typedef void * lib_handle
;
83 open_library(const char *filename
)
85 return dlopen(filename
, RTLD_LAZY
);
89 close_library(void *lib
)
106 * Open the named driver and find its bootstrap function: _eglMain().
109 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
112 _EGLMain_t mainFunc
= NULL
;
113 const char *error
= "unknown error";
117 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
118 lib
= open_library(driverPath
);
120 #if defined(_EGL_OS_WINDOWS)
123 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
124 #elif defined(_EGL_OS_UNIX)
130 /* direct cast gives a warning when compiled with -pedantic */
131 tmp
.ptr
= dlsym(lib
, "_eglMain");
142 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
148 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
161 * Load a module and create the driver object.
164 _eglLoadModule(_EGLModule
*mod
)
174 lib
= (lib_handle
) NULL
;
175 mainFunc
= mod
->BuiltIn
;
178 mainFunc
= _eglOpenLibrary(mod
->Path
, &lib
);
183 drv
= mainFunc(NULL
);
191 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", mod
->Path
);
192 drv
->Name
= "UNNAMED";
195 mod
->Handle
= (void *) lib
;
206 _eglUnloadModule(_EGLModule
*mod
)
208 #if defined(_EGL_OS_UNIX)
209 /* destroy the driver */
210 if (mod
->Driver
&& mod
->Driver
->Unload
)
211 mod
->Driver
->Unload(mod
->Driver
);
214 * XXX At this point (atexit), the module might be the last reference to
215 * libEGL. Closing the module might unmap libEGL and give problems.
219 close_library(mod
->Handle
);
221 #elif defined(_EGL_OS_WINDOWS)
222 /* XXX Windows unloads DLLs before atexit */
231 * Add a module to the module array.
234 _eglAddModule(const char *path
)
240 _eglModules
= _eglCreateArray("Module", 8);
245 /* find duplicates */
246 for (i
= 0; i
< _eglModules
->Size
; i
++) {
247 mod
= _eglModules
->Elements
[i
];
248 if (strcmp(mod
->Path
, path
) == 0)
252 /* allocate a new one */
253 mod
= calloc(1, sizeof(*mod
));
255 mod
->Path
= _eglstrdup(path
);
262 _eglAppendArray(_eglModules
, (void *) mod
);
263 _eglLog(_EGL_DEBUG
, "added %s to module array", mod
->Path
);
274 _eglFreeModule(void *module
)
276 _EGLModule
*mod
= (_EGLModule
*) module
;
278 _eglUnloadModule(mod
);
285 * A loader function for use with _eglPreloadForEach. The loader data is the
286 * filename of the driver. This function stops on the first valid driver.
289 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
292 const char *filename
= (const char *) loader_data
;
293 size_t flen
= strlen(filename
);
295 /* make a full path */
296 if (len
+ flen
+ 2 > sizeof(path
))
299 memcpy(path
, dir
, len
);
302 memcpy(path
+ len
, filename
, flen
);
306 if (library_suffix()) {
307 const char *suffix
= library_suffix();
308 size_t slen
= strlen(suffix
);
310 EGLBoolean need_suffix
;
312 p
= filename
+ flen
- slen
;
313 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
316 if (len
+ slen
+ 1 > sizeof(path
))
318 strcpy(path
+ len
, suffix
);
322 #if defined(_EGL_OS_UNIX)
323 /* check if the file exists */
324 if (access(path
, F_OK
))
335 * Run the callback function on each driver directory.
337 * The process may end prematurely if the callback function returns false.
340 _eglPreloadForEach(const char *search_path
,
341 EGLBoolean (*loader
)(const char *, size_t, void *),
344 const char *cur
, *next
;
349 next
= strchr(cur
, ':');
350 len
= (next
) ? next
- cur
: strlen(cur
);
352 if (!loader(cur
, len
, loader_data
))
355 cur
= (next
) ? next
+ 1 : NULL
;
361 * Return a list of colon-separated driver directories.
364 _eglGetSearchPath(void)
366 static char search_path
[1024];
368 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
369 if (search_path
[0] == '\0') {
370 char *buf
= search_path
;
371 size_t len
= sizeof(search_path
);
376 #if defined(_EGL_OS_UNIX)
377 use_env
= (geteuid() == getuid() && getegid() == getgid());
387 /* extract the dirname from EGL_DRIVER */
388 p
= getenv("EGL_DRIVER");
389 if (p
&& strchr(p
, dir_sep
)) {
390 ret
= _eglsnprintf(buf
, len
, "%s", p
);
391 if (ret
> 0 && ret
< len
) {
392 p
= strrchr(buf
, dir_sep
);
400 /* append EGL_DRIVERS_PATH */
401 p
= getenv("EGL_DRIVERS_PATH");
403 ret
= _eglsnprintf(buf
, len
, "%s:", p
);
404 if (ret
> 0 && ret
< len
) {
412 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
415 ret
= _eglsnprintf(buf
, len
, "%s", _EGL_DRIVER_SEARCH_DIR
);
416 if (ret
< 0 || ret
>= len
)
417 search_path
[0] = '\0';
419 _eglLog(_EGL_DEBUG
, "EGL search path is %s", search_path
);
421 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
428 * Add the user driver to the module array.
430 * The user driver is specified by EGL_DRIVER.
433 _eglAddUserDriver(void)
435 const char *search_path
= _eglGetSearchPath();
438 env
= getenv("EGL_DRIVER");
439 #if defined(_EGL_OS_UNIX)
440 if (env
&& strchr(env
, '/')) {
442 if ((geteuid() != getuid() || getegid() != getgid())) {
444 "ignore EGL_DRIVER for setuid/setgid binaries");
448 #endif /* _EGL_OS_UNIX */
453 /* env can be a path */
454 _eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
);
455 /* or the name of a built-in driver */
456 for (i
= 0; _eglBuiltInDrivers
[i
].name
; i
++) {
457 if (!strcmp(_eglBuiltInDrivers
[i
].name
, env
)) {
458 mod
= _eglAddModule(env
);
460 mod
->BuiltIn
= _eglBuiltInDrivers
[i
].main
;
468 * Add egl_gallium to the module array.
471 _eglAddGalliumDriver(void)
473 #ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
474 void *external
= (void *) "egl_gallium";
475 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile
, external
);
481 * Add built-in drivers to the module array.
484 _eglAddBuiltInDrivers(void)
489 for (i
= 0; _eglBuiltInDrivers
[i
].name
; i
++) {
490 mod
= _eglAddModule(_eglBuiltInDrivers
[i
].name
);
492 mod
->BuiltIn
= _eglBuiltInDrivers
[i
].main
;
498 * Add drivers to the module array. Drivers will be loaded as they are matched
507 /* the order here decides the priorities of the drivers */
509 _eglAddGalliumDriver();
510 _eglAddBuiltInDrivers();
512 return (_eglModules
!= NULL
);
517 * Match a display to a driver. The display is initialized unless use_probe is
520 * The matching is done by finding the first driver that can initialize the
521 * display, or when use_probe is true, the driver with highest score.
524 _eglMatchDriver(_EGLDisplay
*dpy
, EGLBoolean use_probe
)
527 _EGLDriver
*best_drv
= NULL
;
528 EGLint best_score
= 0;
529 EGLint major
, minor
, i
;
531 _eglLockMutex(&_eglModuleMutex
);
533 if (!_eglAddDrivers()) {
534 _eglUnlockMutex(&_eglModuleMutex
);
538 /* match the loaded modules */
539 for (i
= 0; i
< _eglModules
->Size
; i
++) {
540 mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
545 EGLint score
= (mod
->Driver
->Probe
) ?
546 mod
->Driver
->Probe(mod
->Driver
, dpy
) : 1;
547 if (score
> best_score
) {
548 best_drv
= mod
->Driver
;
553 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
, &major
, &minor
)) {
554 best_drv
= mod
->Driver
;
559 if (best_score
>= 100)
563 /* load more modules */
565 EGLint first_unloaded
= i
;
567 while (i
< _eglModules
->Size
) {
568 mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
569 assert(!mod
->Driver
);
571 if (!_eglLoadModule(mod
)) {
572 /* remove invalid modules */
573 _eglEraseArray(_eglModules
, i
, _eglFreeModule
);
578 best_score
= (mod
->Driver
->Probe
) ?
579 mod
->Driver
->Probe(mod
->Driver
, dpy
) : 1;
582 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
, &major
, &minor
))
586 if (best_score
> 0) {
587 best_drv
= mod
->Driver
;
588 /* loaded modules come before unloaded ones */
589 if (first_unloaded
!= i
) {
590 void *tmp
= _eglModules
->Elements
[i
];
591 _eglModules
->Elements
[i
] =
592 _eglModules
->Elements
[first_unloaded
];
593 _eglModules
->Elements
[first_unloaded
] = tmp
;
598 _eglUnloadModule(mod
);
604 _eglUnlockMutex(&_eglModuleMutex
);
607 _eglLog(_EGL_DEBUG
, "the best driver is %s (score %d)",
608 best_drv
->Name
, best_score
);
610 dpy
->Driver
= best_drv
;
611 dpy
->Initialized
= EGL_TRUE
;
612 dpy
->APImajor
= major
;
613 dpy
->APIminor
= minor
;
621 __eglMustCastToProperFunctionPointerType
622 _eglGetDriverProc(const char *procname
)
625 _EGLProc proc
= NULL
;
628 /* load the driver for the default display */
629 EGLDisplay egldpy
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
630 _EGLDisplay
*dpy
= _eglLookupDisplay(egldpy
);
631 if (!dpy
|| !_eglMatchDriver(dpy
, EGL_TRUE
))
635 for (i
= 0; i
< _eglModules
->Size
; i
++) {
636 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
640 proc
= mod
->Driver
->API
.GetProcAddress(mod
->Driver
, procname
);
650 * Unload all drivers.
653 _eglUnloadDrivers(void)
655 /* this is called at atexit time */
657 _eglDestroyArray(_eglModules
, _eglFreeModule
);
664 * Invoke a callback function on each EGL search path.
666 * The first argument of the callback function is the name of the search path.
667 * The second argument is the length of the name.
670 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
673 const char *search_path
= _eglGetSearchPath();
674 _eglPreloadForEach(search_path
, callback
, callback_data
);