2 * Functions for choosing and opening/loading device drivers.
11 #include "eglstring.h"
12 #include "eglconfig.h"
13 #include "eglcontext.h"
14 #include "egldefines.h"
15 #include "egldisplay.h"
16 #include "egldriver.h"
20 #include "eglscreen.h"
21 #include "eglstring.h"
22 #include "eglsurface.h"
27 #if defined(_EGL_OS_UNIX)
29 #include <sys/types.h>
35 typedef struct _egl_module
{
41 static _EGL_DECLARE_MUTEX(_eglModuleMutex
);
42 static _EGLArray
*_eglModules
;
46 * Wrappers for dlopen/dlclose()
48 #if defined(_EGL_OS_WINDOWS)
51 typedef HMODULE lib_handle
;
54 open_library(const char *filename
)
56 return LoadLibrary(filename
);
60 close_library(HMODULE lib
)
73 #elif defined(_EGL_OS_UNIX)
76 typedef void * lib_handle
;
79 open_library(const char *filename
)
81 return dlopen(filename
, RTLD_LAZY
);
85 close_library(void *lib
)
102 * Open the named driver and find its bootstrap function: _eglMain().
105 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
108 _EGLMain_t mainFunc
= NULL
;
109 const char *error
= "unknown error";
113 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
114 lib
= open_library(driverPath
);
116 #if defined(_EGL_OS_WINDOWS)
119 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
120 #elif defined(_EGL_OS_UNIX)
126 /* direct cast gives a warning when compiled with -pedantic */
127 tmp
.ptr
= dlsym(lib
, "_eglMain");
138 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
140 if (!getenv("EGL_DRIVER"))
141 _eglLog(_EGL_WARNING
,
142 "The driver can be overridden by setting EGL_DRIVER");
147 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
160 * Load a module and create the driver object.
163 _eglLoadModule(_EGLModule
*mod
)
169 mainFunc
= _eglOpenLibrary(mod
->Path
, &lib
);
173 drv
= mainFunc(NULL
);
181 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", mod
->Path
);
182 drv
->Name
= "UNNAMED";
185 mod
->Handle
= (void *) lib
;
196 _eglUnloadModule(_EGLModule
*mod
)
198 /* destroy the driver */
199 if (mod
->Driver
&& mod
->Driver
->Unload
)
200 mod
->Driver
->Unload(mod
->Driver
);
202 close_library(mod
->Handle
);
210 * Add a module to the module array.
213 _eglAddModule(const char *path
)
219 _eglModules
= _eglCreateArray("Module", 8);
224 /* find duplicates */
225 for (i
= 0; i
< _eglModules
->Size
; i
++) {
226 mod
= _eglModules
->Elements
[i
];
227 if (strcmp(mod
->Path
, path
) == 0)
231 /* allocate a new one */
232 mod
= calloc(1, sizeof(*mod
));
234 mod
->Path
= _eglstrdup(path
);
241 _eglAppendArray(_eglModules
, (void *) mod
);
242 _eglLog(_EGL_DEBUG
, "added %s to module array", mod
->Path
);
253 _eglFreeModule(void *module
)
255 _EGLModule
*mod
= (_EGLModule
*) module
;
257 _eglUnloadModule(mod
);
264 * A loader function for use with _eglPreloadForEach. The loader data is the
265 * filename of the driver. This function stops on the first valid driver.
268 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
271 const char *filename
= (const char *) loader_data
;
272 size_t flen
= strlen(filename
);
274 /* make a full path */
275 if (len
+ flen
+ 2 > sizeof(path
))
278 memcpy(path
, dir
, len
);
281 memcpy(path
+ len
, filename
, flen
);
285 if (library_suffix()) {
286 const char *suffix
= library_suffix();
287 size_t slen
= strlen(suffix
);
289 EGLBoolean need_suffix
;
291 p
= filename
+ flen
- slen
;
292 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
295 if (len
+ slen
+ 1 > sizeof(path
))
297 strcpy(path
+ len
, suffix
);
301 #if defined(_EGL_OS_UNIX)
302 /* check if the file exists */
303 if (access(path
, F_OK
))
314 * A loader function for use with _eglPreloadForEach. The loader data is the
315 * pattern (prefix) of the files to look for.
318 _eglLoaderPattern(const char *dir
, size_t len
, void *loader_data
)
320 #if defined(_EGL_OS_UNIX)
321 const char *prefix
, *suffix
;
322 size_t prefix_len
, suffix_len
;
324 struct dirent
*dirent
;
327 if (len
+ 2 > sizeof(path
))
330 memcpy(path
, dir
, len
);
335 dirp
= opendir(path
);
339 prefix
= (const char *) loader_data
;
340 prefix_len
= strlen(prefix
);
341 suffix
= library_suffix();
342 suffix_len
= (suffix
) ? strlen(suffix
) : 0;
344 while ((dirent
= readdir(dirp
))) {
345 size_t dirent_len
= strlen(dirent
->d_name
);
348 /* match the prefix */
349 if (strncmp(dirent
->d_name
, prefix
, prefix_len
) != 0)
351 /* match the suffix */
353 p
= dirent
->d_name
+ dirent_len
- suffix_len
;
354 if (p
< dirent
->d_name
|| strcmp(p
, suffix
) != 0)
358 /* make a full path and add it to the module array */
359 if (len
+ dirent_len
+ 1 <= sizeof(path
)) {
360 strcpy(path
+ len
, dirent
->d_name
);
368 #else /* _EGL_OS_UNIX */
369 /* stop immediately */
376 * Run the callback function on each driver directory.
378 * The process may end prematurely if the callback function returns false.
381 _eglPreloadForEach(const char *search_path
,
382 EGLBoolean (*loader
)(const char *, size_t, void *),
385 const char *cur
, *next
;
390 next
= strchr(cur
, ':');
391 len
= (next
) ? next
- cur
: strlen(cur
);
393 if (!loader(cur
, len
, loader_data
))
396 cur
= (next
) ? next
+ 1 : NULL
;
402 * Return a list of colon-separated driver directories.
405 _eglGetSearchPath(void)
407 static const char *search_path
;
409 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
411 static char buffer
[1024];
415 p
= getenv("EGL_DRIVERS_PATH");
416 #if defined(_EGL_OS_UNIX)
417 if (p
&& (geteuid() != getuid() || getegid() != getgid())) {
419 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
422 #endif /* _EGL_OS_UNIX */
425 ret
= _eglsnprintf(buffer
, sizeof(buffer
),
426 "%s:%s", p
, _EGL_DRIVER_SEARCH_DIR
);
427 if (ret
> 0 && ret
< sizeof(buffer
))
428 search_path
= buffer
;
432 search_path
= _EGL_DRIVER_SEARCH_DIR
;
442 * Add the user driver to the module array.
444 * The user driver is specified by EGL_DRIVER.
447 _eglAddUserDriver(void)
449 const char *search_path
= _eglGetSearchPath();
452 env
= getenv("EGL_DRIVER");
453 #if defined(_EGL_OS_UNIX)
454 if (env
&& strchr(env
, '/')) {
456 if ((geteuid() != getuid() || getegid() != getgid())) {
458 "ignore EGL_DRIVER for setuid/setgid binaries");
462 #endif /* _EGL_OS_UNIX */
464 _eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
);
469 * Add default drivers to the module array.
472 _eglAddDefaultDrivers(void)
474 const char *search_path
= _eglGetSearchPath();
476 #if defined(_EGL_OS_WINDOWS)
477 const char *DefaultDriverNames
[] = {
480 #elif defined(_EGL_OS_UNIX)
481 const char *DefaultDriverNames
[] = {
488 for (i
= 0; i
< ARRAY_SIZE(DefaultDriverNames
); i
++) {
489 void *name
= (void *) DefaultDriverNames
[i
];
490 _eglPreloadForEach(search_path
, _eglLoaderFile
, name
);
496 * Add drivers to the module array. Drivers will be loaded as they are matched
505 /* the order here decides the priorities of the drivers */
507 _eglAddDefaultDrivers();
508 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderPattern
, (void *) "egl_");
510 return (_eglModules
!= NULL
);
515 * Match a display to a driver. The display is initialized unless use_probe is
518 * The matching is done by finding the first driver that can initialize the
519 * display, or when use_probe is true, the driver with highest score.
522 _eglMatchDriver(_EGLDisplay
*dpy
, EGLBoolean use_probe
)
525 _EGLDriver
*best_drv
= NULL
;
526 EGLint best_score
= 0;
527 EGLint major
, minor
, i
;
529 _eglLockMutex(&_eglModuleMutex
);
531 if (!_eglAddDrivers()) {
532 _eglUnlockMutex(&_eglModuleMutex
);
536 /* match the loaded modules */
537 for (i
= 0; i
< _eglModules
->Size
; i
++) {
538 mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
543 EGLint score
= (mod
->Driver
->Probe
) ?
544 mod
->Driver
->Probe(mod
->Driver
, dpy
) : 1;
545 if (score
> best_score
) {
546 best_drv
= mod
->Driver
;
551 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
, &major
, &minor
)) {
552 best_drv
= mod
->Driver
;
557 if (best_score
>= 100)
561 /* load more modules */
563 EGLint first_unloaded
= i
;
565 while (i
< _eglModules
->Size
) {
566 mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
567 assert(!mod
->Driver
);
569 if (!_eglLoadModule(mod
)) {
570 /* remove invalid modules */
571 _eglEraseArray(_eglModules
, i
, _eglFreeModule
);
576 best_score
= (mod
->Driver
->Probe
) ?
577 mod
->Driver
->Probe(mod
->Driver
, dpy
) : 1;
580 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
, &major
, &minor
))
584 if (best_score
> 0) {
585 best_drv
= mod
->Driver
;
586 /* loaded modules come before unloaded ones */
587 if (first_unloaded
!= i
) {
588 void *tmp
= _eglModules
->Elements
[i
];
589 _eglModules
->Elements
[i
] =
590 _eglModules
->Elements
[first_unloaded
];
591 _eglModules
->Elements
[first_unloaded
] = tmp
;
596 _eglUnloadModule(mod
);
602 _eglUnlockMutex(&_eglModuleMutex
);
605 _eglLog(_EGL_DEBUG
, "the best driver is %s (score %d)",
606 best_drv
->Name
, best_score
);
608 dpy
->Driver
= best_drv
;
609 dpy
->Initialized
= EGL_TRUE
;
610 dpy
->APImajor
= major
;
611 dpy
->APIminor
= minor
;
619 __eglMustCastToProperFunctionPointerType
620 _eglGetDriverProc(const char *procname
)
623 _EGLProc proc
= NULL
;
626 /* load the driver for the default display */
627 EGLDisplay egldpy
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
628 _EGLDisplay
*dpy
= _eglLookupDisplay(egldpy
);
629 if (!dpy
|| !_eglMatchDriver(dpy
, EGL_TRUE
))
633 for (i
= 0; i
< _eglModules
->Size
; i
++) {
634 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
638 proc
= mod
->Driver
->API
.GetProcAddress(mod
->Driver
, procname
);
648 * Unload all drivers.
651 _eglUnloadDrivers(void)
653 /* this is called at atexit time */
655 #if defined(_EGL_OS_UNIX)
656 _eglDestroyArray(_eglModules
, _eglFreeModule
);
657 #elif defined(_EGL_OS_WINDOWS)
658 /* XXX Windows unloads DLLs before atexit */
659 _eglDestroyArray(_eglModules
, NULL
);
667 * Plug all the available fallback routines into the given driver's
671 _eglInitDriverFallbacks(_EGLDriver
*drv
)
673 /* If a pointer is set to NULL, then the device driver _really_ has
676 drv
->API
.Initialize
= NULL
;
677 drv
->API
.Terminate
= NULL
;
679 drv
->API
.GetConfigs
= _eglGetConfigs
;
680 drv
->API
.ChooseConfig
= _eglChooseConfig
;
681 drv
->API
.GetConfigAttrib
= _eglGetConfigAttrib
;
683 drv
->API
.CreateContext
= _eglCreateContext
;
684 drv
->API
.DestroyContext
= _eglDestroyContext
;
685 drv
->API
.MakeCurrent
= _eglMakeCurrent
;
686 drv
->API
.QueryContext
= _eglQueryContext
;
688 drv
->API
.CreateWindowSurface
= _eglCreateWindowSurface
;
689 drv
->API
.CreatePixmapSurface
= _eglCreatePixmapSurface
;
690 drv
->API
.CreatePbufferSurface
= _eglCreatePbufferSurface
;
691 drv
->API
.DestroySurface
= _eglDestroySurface
;
692 drv
->API
.QuerySurface
= _eglQuerySurface
;
693 drv
->API
.SurfaceAttrib
= _eglSurfaceAttrib
;
694 drv
->API
.BindTexImage
= _eglBindTexImage
;
695 drv
->API
.ReleaseTexImage
= _eglReleaseTexImage
;
696 drv
->API
.SwapInterval
= _eglSwapInterval
;
697 drv
->API
.SwapBuffers
= _eglSwapBuffers
;
698 drv
->API
.CopyBuffers
= _eglCopyBuffers
;
700 drv
->API
.QueryString
= _eglQueryString
;
701 drv
->API
.WaitClient
= _eglWaitClient
;
702 drv
->API
.WaitNative
= _eglWaitNative
;
704 #ifdef EGL_MESA_screen_surface
705 drv
->API
.ChooseModeMESA
= _eglChooseModeMESA
;
706 drv
->API
.GetModesMESA
= _eglGetModesMESA
;
707 drv
->API
.GetModeAttribMESA
= _eglGetModeAttribMESA
;
708 drv
->API
.GetScreensMESA
= _eglGetScreensMESA
;
709 drv
->API
.CreateScreenSurfaceMESA
= _eglCreateScreenSurfaceMESA
;
710 drv
->API
.ShowScreenSurfaceMESA
= _eglShowScreenSurfaceMESA
;
711 drv
->API
.ScreenPositionMESA
= _eglScreenPositionMESA
;
712 drv
->API
.QueryScreenMESA
= _eglQueryScreenMESA
;
713 drv
->API
.QueryScreenSurfaceMESA
= _eglQueryScreenSurfaceMESA
;
714 drv
->API
.QueryScreenModeMESA
= _eglQueryScreenModeMESA
;
715 drv
->API
.QueryModeStringMESA
= _eglQueryModeStringMESA
;
716 #endif /* EGL_MESA_screen_surface */
718 #ifdef EGL_VERSION_1_2
719 drv
->API
.CreatePbufferFromClientBuffer
= _eglCreatePbufferFromClientBuffer
;
720 #endif /* EGL_VERSION_1_2 */
722 #ifdef EGL_KHR_image_base
723 drv
->API
.CreateImageKHR
= _eglCreateImageKHR
;
724 drv
->API
.DestroyImageKHR
= _eglDestroyImageKHR
;
725 #endif /* EGL_KHR_image_base */
727 #ifdef EGL_KHR_reusable_sync
728 drv
->API
.CreateSyncKHR
= _eglCreateSyncKHR
;
729 drv
->API
.DestroySyncKHR
= _eglDestroySyncKHR
;
730 drv
->API
.ClientWaitSyncKHR
= _eglClientWaitSyncKHR
;
731 drv
->API
.SignalSyncKHR
= _eglSignalSyncKHR
;
732 drv
->API
.GetSyncAttribKHR
= _eglGetSyncAttribKHR
;
733 #endif /* EGL_KHR_reusable_sync */
738 * Invoke a callback function on each EGL search path.
740 * The first argument of the callback function is the name of the search path.
741 * The second argument is the length of the name.
744 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
747 const char *search_path
= _eglGetSearchPath();
748 _eglPreloadForEach(search_path
, callback
, callback_data
);