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"
17 #include "eglglobals.h"
21 #include "eglscreen.h"
22 #include "eglstring.h"
23 #include "eglsurface.h"
26 #if defined(_EGL_PLATFORM_POSIX)
28 #include <sys/types.h>
35 * Wrappers for dlopen/dlclose()
37 #if defined(_EGL_PLATFORM_WINDOWS)
40 /* XXX Need to decide how to do dynamic name lookup on Windows */
41 static const char *DefaultDriverNames
[] = {
45 typedef HMODULE lib_handle
;
48 open_library(const char *filename
)
50 return LoadLibrary(filename
);
54 close_library(HMODULE lib
)
67 #elif defined(_EGL_PLATFORM_POSIX)
70 static const char *DefaultDriverNames
[] = {
75 typedef void * lib_handle
;
78 open_library(const char *filename
)
80 return dlopen(filename
, RTLD_LAZY
);
84 close_library(void *lib
)
100 #define NUM_PROBE_CACHE_SLOTS 8
102 EGLint keys
[NUM_PROBE_CACHE_SLOTS
];
103 const void *values
[NUM_PROBE_CACHE_SLOTS
];
108 * Open the named driver and find its bootstrap function: _eglMain().
111 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
114 _EGLMain_t mainFunc
= NULL
;
115 const char *error
= "unknown error";
119 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
120 lib
= open_library(driverPath
);
122 #if defined(_EGL_PLATFORM_WINDOWS)
125 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
126 #elif defined(_EGL_PLATFORM_POSIX)
132 /* direct cast gives a warning when compiled with -pedantic */
133 tmp
.ptr
= dlsym(lib
, "_eglMain");
144 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
146 if (!getenv("EGL_DRIVER"))
147 _eglLog(_EGL_WARNING
,
148 "The driver can be overridden by setting EGL_DRIVER");
153 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
166 * Load the named driver.
169 _eglLoadDriver(const char *path
, const char *args
)
173 _EGLDriver
*drv
= NULL
;
175 mainFunc
= _eglOpenLibrary(path
, &lib
);
179 drv
= mainFunc(args
);
187 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", path
);
188 drv
->Name
= "UNNAMED";
191 drv
->Path
= _eglstrdup(path
);
192 drv
->Args
= (args
) ? _eglstrdup(args
) : NULL
;
193 if (!drv
->Path
|| (args
&& !drv
->Args
)) {
195 free((char *) drv
->Path
);
197 free((char *) drv
->Args
);
204 drv
->LibHandle
= lib
;
211 * Match a display to a preloaded driver.
213 * The matching is done by finding the driver with the highest score.
216 _eglMatchDriver(_EGLDisplay
*dpy
)
218 _EGLDriver
*best_drv
= NULL
;
219 EGLint best_score
= -1, i
;
222 * this function is called after preloading and the drivers never change
225 for (i
= 0; i
< _eglGlobal
.NumDrivers
; i
++) {
226 _EGLDriver
*drv
= _eglGlobal
.Drivers
[i
];
229 score
= (drv
->Probe
) ? drv
->Probe(drv
, dpy
) : 0;
230 if (score
> best_score
) {
232 _eglLog(_EGL_DEBUG
, "driver %s has higher score than %s",
233 drv
->Name
, best_drv
->Name
);
249 * A loader function for use with _eglPreloadForEach. The loader data is the
250 * filename of the driver. This function stops on the first valid driver.
253 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
257 const char *filename
= (const char *) loader_data
;
258 size_t flen
= strlen(filename
);
260 /* make a full path */
261 if (len
+ flen
+ 2 > sizeof(path
))
264 memcpy(path
, dir
, len
);
267 memcpy(path
+ len
, filename
, flen
);
271 if (library_suffix() == NULL
|| strstr(path
, library_suffix()))
272 drv
= _eglLoadDriver(path
, NULL
);
274 const char *suffix
= library_suffix();
275 size_t slen
= strlen(suffix
);
277 EGLBoolean need_suffix
;
279 p
= filename
+ flen
- slen
;
280 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
281 if (need_suffix
&& len
+ slen
+ 1 <= sizeof(path
)) {
282 strcpy(path
+ len
, suffix
);
283 drv
= _eglLoadDriver(path
, NULL
);
291 /* remember the driver and stop */
292 _eglGlobal
.Drivers
[_eglGlobal
.NumDrivers
++] = drv
;
298 * A loader function for use with _eglPreloadForEach. The loader data is the
299 * pattern (prefix) of the files to look for.
302 _eglLoaderPattern(const char *dir
, size_t len
, void *loader_data
)
304 #if defined(_EGL_PLATFORM_POSIX)
305 const char *prefix
, *suffix
;
306 size_t prefix_len
, suffix_len
;
308 struct dirent
*dirent
;
311 if (len
+ 2 > sizeof(path
))
314 memcpy(path
, dir
, len
);
319 dirp
= opendir(path
);
323 prefix
= (const char *) loader_data
;
324 prefix_len
= strlen(prefix
);
325 suffix
= library_suffix();
326 suffix_len
= (suffix
) ? strlen(suffix
) : 0;
328 while ((dirent
= readdir(dirp
))) {
330 size_t dirent_len
= strlen(dirent
->d_name
);
333 /* match the prefix */
334 if (strncmp(dirent
->d_name
, prefix
, prefix_len
) != 0)
336 /* match the suffix */
338 p
= dirent
->d_name
+ dirent_len
- suffix_len
;
339 if (p
< dirent
->d_name
|| strcmp(p
, suffix
) != 0)
343 /* make a full path and load the driver */
344 if (len
+ dirent_len
+ 1 <= sizeof(path
)) {
345 strcpy(path
+ len
, dirent
->d_name
);
346 drv
= _eglLoadDriver(path
, NULL
);
348 _eglGlobal
.Drivers
[_eglGlobal
.NumDrivers
++] = drv
;
355 #else /* _EGL_PLATFORM_POSIX */
356 /* stop immediately */
363 * Run the preload function on each driver directory and return the number of
366 * The process may end prematurely if the callback function returns false.
369 _eglPreloadForEach(const char *search_path
,
370 EGLBoolean (*loader
)(const char *, size_t, void *),
373 const char *cur
, *next
;
375 EGLint num_drivers
= _eglGlobal
.NumDrivers
;
379 next
= strchr(cur
, ':');
380 len
= (next
) ? next
- cur
: strlen(cur
);
382 if (!loader(cur
, len
, loader_data
))
385 cur
= (next
) ? next
+ 1 : NULL
;
388 return (_eglGlobal
.NumDrivers
- num_drivers
);
393 * Return a list of colon-separated driver directories.
396 _eglGetSearchPath(void)
398 static const char *search_path
;
400 #if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS)
402 static char buffer
[1024];
406 p
= getenv("EGL_DRIVERS_PATH");
407 #if defined(_EGL_PLATFORM_POSIX)
408 if (p
&& (geteuid() != getuid() || getegid() != getgid())) {
410 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
413 #endif /* _EGL_PLATFORM_POSIX */
416 ret
= _eglsnprintf(buffer
, sizeof(buffer
),
417 "%s:%s", p
, _EGL_DRIVER_SEARCH_DIR
);
418 if (ret
> 0 && ret
< sizeof(buffer
))
419 search_path
= buffer
;
423 search_path
= _EGL_DRIVER_SEARCH_DIR
;
433 * Preload a user driver.
435 * A user driver can be specified by EGL_DRIVER.
438 _eglPreloadUserDriver(void)
440 const char *search_path
= _eglGetSearchPath();
443 env
= getenv("EGL_DRIVER");
444 #if defined(_EGL_PLATFORM_POSIX)
445 if (env
&& strchr(env
, '/')) {
447 if ((geteuid() != getuid() || getegid() != getgid())) {
449 "ignore EGL_DRIVER for setuid/setgid binaries");
453 #endif /* _EGL_PLATFORM_POSIX */
457 if (!_eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
)) {
458 _eglLog(_EGL_WARNING
, "EGL_DRIVER is set to an invalid driver");
467 * Preload display drivers.
469 * Display drivers are a set of drivers that support a certain display system.
470 * The display system may be specified by EGL_DISPLAY.
472 * FIXME This makes libEGL a memory hog if an user driver is not specified and
473 * there are many display drivers.
476 _eglPreloadDisplayDrivers(void)
482 dpy
= getenv("EGL_DISPLAY");
484 dpy
= _EGL_DEFAULT_DISPLAY
;
488 ret
= _eglsnprintf(prefix
, sizeof(prefix
), "egl_%s_", dpy
);
489 if (ret
< 0 || ret
>= sizeof(prefix
))
492 return (_eglPreloadForEach(_eglGetSearchPath(),
493 _eglLoaderPattern
, (void *) prefix
) > 0);
500 * This function loads the driver modules and creates the corresponding
501 * _EGLDriver objects.
504 _eglPreloadDrivers(void)
508 /* protect the preloading process */
509 _eglLockMutex(_eglGlobal
.Mutex
);
511 /* already preloaded */
512 if (_eglGlobal
.NumDrivers
) {
513 _eglUnlockMutex(_eglGlobal
.Mutex
);
517 loaded
= (_eglPreloadUserDriver() ||
518 _eglPreloadDisplayDrivers());
520 _eglUnlockMutex(_eglGlobal
.Mutex
);
526 * Unload preloaded drivers.
529 _eglUnloadDrivers(void)
533 /* this is called at atexit time */
534 for (i
= 0; i
< _eglGlobal
.NumDrivers
; i
++) {
535 _EGLDriver
*drv
= _eglGlobal
.Drivers
[i
];
536 lib_handle handle
= drv
->LibHandle
;
539 free((char *) drv
->Path
);
541 free((char *) drv
->Args
);
548 close_library(handle
);
549 _eglGlobal
.Drivers
[i
] = NULL
;
552 _eglGlobal
.NumDrivers
= 0;
556 _eglLoadDefaultDriver(EGLDisplay dpy
, EGLint
*major
, EGLint
*minor
)
558 _EGLDriver
*drv
= NULL
;
561 _eglLockMutex(_eglGlobal
.Mutex
);
563 for (i
= 0; i
< ARRAY_SIZE(DefaultDriverNames
); i
++) {
564 _eglPreloadForEach(_eglGetSearchPath(),
565 _eglLoaderFile
, (void *) DefaultDriverNames
[i
]);
566 if (_eglGlobal
.NumDrivers
== 0)
568 drv
= _eglGlobal
.Drivers
[0];
569 if (drv
->API
.Initialize(drv
, dpy
, major
, minor
))
574 _eglUnlockMutex(_eglGlobal
.Mutex
);
576 return _eglGlobal
.NumDrivers
> 0 ? drv
: NULL
;
581 * Plug all the available fallback routines into the given driver's
585 _eglInitDriverFallbacks(_EGLDriver
*drv
)
587 /* If a pointer is set to NULL, then the device driver _really_ has
590 drv
->API
.Initialize
= NULL
;
591 drv
->API
.Terminate
= NULL
;
593 drv
->API
.GetConfigs
= _eglGetConfigs
;
594 drv
->API
.ChooseConfig
= _eglChooseConfig
;
595 drv
->API
.GetConfigAttrib
= _eglGetConfigAttrib
;
597 drv
->API
.CreateContext
= _eglCreateContext
;
598 drv
->API
.DestroyContext
= _eglDestroyContext
;
599 drv
->API
.MakeCurrent
= _eglMakeCurrent
;
600 drv
->API
.QueryContext
= _eglQueryContext
;
602 drv
->API
.CreateWindowSurface
= _eglCreateWindowSurface
;
603 drv
->API
.CreatePixmapSurface
= _eglCreatePixmapSurface
;
604 drv
->API
.CreatePbufferSurface
= _eglCreatePbufferSurface
;
605 drv
->API
.DestroySurface
= _eglDestroySurface
;
606 drv
->API
.QuerySurface
= _eglQuerySurface
;
607 drv
->API
.SurfaceAttrib
= _eglSurfaceAttrib
;
608 drv
->API
.BindTexImage
= _eglBindTexImage
;
609 drv
->API
.ReleaseTexImage
= _eglReleaseTexImage
;
610 drv
->API
.SwapInterval
= _eglSwapInterval
;
611 drv
->API
.SwapBuffers
= _eglSwapBuffers
;
612 drv
->API
.CopyBuffers
= _eglCopyBuffers
;
614 drv
->API
.QueryString
= _eglQueryString
;
615 drv
->API
.WaitClient
= _eglWaitClient
;
616 drv
->API
.WaitNative
= _eglWaitNative
;
618 #ifdef EGL_MESA_screen_surface
619 drv
->API
.ChooseModeMESA
= _eglChooseModeMESA
;
620 drv
->API
.GetModesMESA
= _eglGetModesMESA
;
621 drv
->API
.GetModeAttribMESA
= _eglGetModeAttribMESA
;
622 drv
->API
.GetScreensMESA
= _eglGetScreensMESA
;
623 drv
->API
.CreateScreenSurfaceMESA
= _eglCreateScreenSurfaceMESA
;
624 drv
->API
.ShowScreenSurfaceMESA
= _eglShowScreenSurfaceMESA
;
625 drv
->API
.ScreenPositionMESA
= _eglScreenPositionMESA
;
626 drv
->API
.QueryScreenMESA
= _eglQueryScreenMESA
;
627 drv
->API
.QueryScreenSurfaceMESA
= _eglQueryScreenSurfaceMESA
;
628 drv
->API
.QueryScreenModeMESA
= _eglQueryScreenModeMESA
;
629 drv
->API
.QueryModeStringMESA
= _eglQueryModeStringMESA
;
630 #endif /* EGL_MESA_screen_surface */
632 #ifdef EGL_VERSION_1_2
633 drv
->API
.CreatePbufferFromClientBuffer
= _eglCreatePbufferFromClientBuffer
;
634 #endif /* EGL_VERSION_1_2 */
636 #ifdef EGL_KHR_image_base
637 drv
->API
.CreateImageKHR
= _eglCreateImageKHR
;
638 drv
->API
.DestroyImageKHR
= _eglDestroyImageKHR
;
639 #endif /* EGL_KHR_image_base */
644 * Invoke a callback function on each EGL search path.
646 * The first argument of the callback function is the name of the search path.
647 * The second argument is the length of the name.
650 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
653 const char *search_path
= _eglGetSearchPath();
654 _eglPreloadForEach(search_path
, callback
, callback_data
);
659 * Set the probe cache at the given key.
661 * A key, instead of a _EGLDriver, is used to allow the probe cache to be share
662 * by multiple drivers.
665 _eglSetProbeCache(EGLint key
, const void *val
)
669 for (idx
= 0; idx
< NUM_PROBE_CACHE_SLOTS
; idx
++) {
670 if (!_eglProbeCache
.keys
[idx
] || _eglProbeCache
.keys
[idx
] == key
)
674 assert(idx
< NUM_PROBE_CACHE_SLOTS
);
676 _eglProbeCache
.keys
[idx
] = key
;
677 _eglProbeCache
.values
[idx
] = val
;
682 * Return the probe cache at the given key.
685 _eglGetProbeCache(EGLint key
)
689 for (idx
= 0; idx
< NUM_PROBE_CACHE_SLOTS
; idx
++) {
690 if (!_eglProbeCache
.keys
[idx
] || _eglProbeCache
.keys
[idx
] == key
)
694 return (idx
< NUM_PROBE_CACHE_SLOTS
&& _eglProbeCache
.keys
[idx
] == key
) ?
695 _eglProbeCache
.values
[idx
] : NULL
;