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_OS_UNIX)
28 #include <sys/types.h>
35 * Wrappers for dlopen/dlclose()
37 #if defined(_EGL_OS_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_OS_UNIX)
70 static const char *DefaultDriverNames
[] = {
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 the named driver.
163 _eglLoadDriver(const char *path
, const char *args
)
167 _EGLDriver
*drv
= NULL
;
169 mainFunc
= _eglOpenLibrary(path
, &lib
);
173 drv
= mainFunc(args
);
181 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", path
);
182 drv
->Name
= "UNNAMED";
185 drv
->Path
= _eglstrdup(path
);
186 drv
->Args
= (args
) ? _eglstrdup(args
) : NULL
;
187 if (!drv
->Path
|| (args
&& !drv
->Args
)) {
189 free((char *) drv
->Path
);
191 free((char *) drv
->Args
);
198 drv
->LibHandle
= lib
;
205 * Match a display to a preloaded driver.
207 * The matching is done by finding the driver with the highest score.
210 _eglMatchDriver(_EGLDisplay
*dpy
)
212 _EGLDriver
*best_drv
= NULL
;
213 EGLint best_score
= -1, i
;
216 * this function is called after preloading and the drivers never change
219 for (i
= 0; i
< _eglGlobal
.NumDrivers
; i
++) {
220 _EGLDriver
*drv
= _eglGlobal
.Drivers
[i
];
223 score
= (drv
->Probe
) ? drv
->Probe(drv
, dpy
) : 0;
224 if (score
> best_score
) {
226 _eglLog(_EGL_DEBUG
, "driver %s has higher score than %s",
227 drv
->Name
, best_drv
->Name
);
243 * A loader function for use with _eglPreloadForEach. The loader data is the
244 * filename of the driver. This function stops on the first valid driver.
247 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
251 const char *filename
= (const char *) loader_data
;
252 size_t flen
= strlen(filename
);
254 /* make a full path */
255 if (len
+ flen
+ 2 > sizeof(path
))
258 memcpy(path
, dir
, len
);
261 memcpy(path
+ len
, filename
, flen
);
265 if (library_suffix() == NULL
|| strstr(path
, library_suffix()))
266 drv
= _eglLoadDriver(path
, NULL
);
268 const char *suffix
= library_suffix();
269 size_t slen
= strlen(suffix
);
271 EGLBoolean need_suffix
;
273 p
= filename
+ flen
- slen
;
274 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
275 if (need_suffix
&& len
+ slen
+ 1 <= sizeof(path
)) {
276 strcpy(path
+ len
, suffix
);
277 drv
= _eglLoadDriver(path
, NULL
);
285 /* remember the driver and stop */
286 _eglGlobal
.Drivers
[_eglGlobal
.NumDrivers
++] = drv
;
292 * Run the preload function on each driver directory and return the number of
295 * The process may end prematurely if the callback function returns false.
298 _eglPreloadForEach(const char *search_path
,
299 EGLBoolean (*loader
)(const char *, size_t, void *),
302 const char *cur
, *next
;
304 EGLint num_drivers
= _eglGlobal
.NumDrivers
;
308 next
= strchr(cur
, ':');
309 len
= (next
) ? next
- cur
: strlen(cur
);
311 if (!loader(cur
, len
, loader_data
))
314 cur
= (next
) ? next
+ 1 : NULL
;
317 return (_eglGlobal
.NumDrivers
- num_drivers
);
322 * Return a list of colon-separated driver directories.
325 _eglGetSearchPath(void)
327 static const char *search_path
;
329 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
331 static char buffer
[1024];
335 p
= getenv("EGL_DRIVERS_PATH");
336 #if defined(_EGL_OS_UNIX)
337 if (p
&& (geteuid() != getuid() || getegid() != getgid())) {
339 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
342 #endif /* _EGL_OS_UNIX */
345 ret
= _eglsnprintf(buffer
, sizeof(buffer
),
346 "%s:%s", p
, _EGL_DRIVER_SEARCH_DIR
);
347 if (ret
> 0 && ret
< sizeof(buffer
))
348 search_path
= buffer
;
352 search_path
= _EGL_DRIVER_SEARCH_DIR
;
362 * Preload a user driver.
364 * A user driver can be specified by EGL_DRIVER.
367 _eglPreloadUserDriver(void)
369 const char *search_path
= _eglGetSearchPath();
372 env
= getenv("EGL_DRIVER");
373 #if defined(_EGL_OS_UNIX)
374 if (env
&& strchr(env
, '/')) {
376 if ((geteuid() != getuid() || getegid() != getgid())) {
378 "ignore EGL_DRIVER for setuid/setgid binaries");
382 #endif /* _EGL_OS_UNIX */
386 if (!_eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
)) {
387 _eglLog(_EGL_WARNING
, "EGL_DRIVER is set to an invalid driver");
398 * This function loads the driver modules and creates the corresponding
399 * _EGLDriver objects.
402 _eglPreloadDrivers(void)
406 /* protect the preloading process */
407 _eglLockMutex(_eglGlobal
.Mutex
);
409 /* already preloaded */
410 if (_eglGlobal
.NumDrivers
) {
411 _eglUnlockMutex(_eglGlobal
.Mutex
);
415 loaded
= _eglPreloadUserDriver();
417 _eglUnlockMutex(_eglGlobal
.Mutex
);
423 * Unload preloaded drivers.
426 _eglUnloadDrivers(void)
428 #if defined(_EGL_OS_UNIX)
431 /* this is called at atexit time */
432 for (i
= 0; i
< _eglGlobal
.NumDrivers
; i
++) {
433 _EGLDriver
*drv
= _eglGlobal
.Drivers
[i
];
434 lib_handle handle
= drv
->LibHandle
;
437 free((char *) drv
->Path
);
439 free((char *) drv
->Args
);
446 close_library(handle
);
447 _eglGlobal
.Drivers
[i
] = NULL
;
450 _eglGlobal
.NumDrivers
= 0;
451 #elif defined(_EGL_OS_WINDOWS)
452 /* XXX Windows unloads DLLs before atexit */
457 _eglLoadDefaultDriver(EGLDisplay dpy
, EGLint
*major
, EGLint
*minor
)
459 _EGLDriver
*drv
= NULL
;
463 _eglLockMutex(_eglGlobal
.Mutex
);
465 for (i
= 0; i
< ARRAY_SIZE(DefaultDriverNames
); i
++) {
466 _eglPreloadForEach(_eglGetSearchPath(),
467 _eglLoaderFile
, (void *) DefaultDriverNames
[i
]);
468 if (_eglGlobal
.NumDrivers
== 0)
470 drv
= _eglGlobal
.Drivers
[0];
472 _eglUnlockMutex(_eglGlobal
.Mutex
);
473 ok
= drv
->API
.Initialize(drv
, dpy
, major
, minor
);
474 _eglLockMutex(_eglGlobal
.Mutex
);
481 _eglUnlockMutex(_eglGlobal
.Mutex
);
483 return _eglGlobal
.NumDrivers
> 0 ? drv
: NULL
;
488 * Plug all the available fallback routines into the given driver's
492 _eglInitDriverFallbacks(_EGLDriver
*drv
)
494 /* If a pointer is set to NULL, then the device driver _really_ has
497 drv
->API
.Initialize
= NULL
;
498 drv
->API
.Terminate
= NULL
;
500 drv
->API
.GetConfigs
= _eglGetConfigs
;
501 drv
->API
.ChooseConfig
= _eglChooseConfig
;
502 drv
->API
.GetConfigAttrib
= _eglGetConfigAttrib
;
504 drv
->API
.CreateContext
= _eglCreateContext
;
505 drv
->API
.DestroyContext
= _eglDestroyContext
;
506 drv
->API
.MakeCurrent
= _eglMakeCurrent
;
507 drv
->API
.QueryContext
= _eglQueryContext
;
509 drv
->API
.CreateWindowSurface
= _eglCreateWindowSurface
;
510 drv
->API
.CreatePixmapSurface
= _eglCreatePixmapSurface
;
511 drv
->API
.CreatePbufferSurface
= _eglCreatePbufferSurface
;
512 drv
->API
.DestroySurface
= _eglDestroySurface
;
513 drv
->API
.QuerySurface
= _eglQuerySurface
;
514 drv
->API
.SurfaceAttrib
= _eglSurfaceAttrib
;
515 drv
->API
.BindTexImage
= _eglBindTexImage
;
516 drv
->API
.ReleaseTexImage
= _eglReleaseTexImage
;
517 drv
->API
.SwapInterval
= _eglSwapInterval
;
518 drv
->API
.SwapBuffers
= _eglSwapBuffers
;
519 drv
->API
.CopyBuffers
= _eglCopyBuffers
;
521 drv
->API
.QueryString
= _eglQueryString
;
522 drv
->API
.WaitClient
= _eglWaitClient
;
523 drv
->API
.WaitNative
= _eglWaitNative
;
525 #ifdef EGL_MESA_screen_surface
526 drv
->API
.ChooseModeMESA
= _eglChooseModeMESA
;
527 drv
->API
.GetModesMESA
= _eglGetModesMESA
;
528 drv
->API
.GetModeAttribMESA
= _eglGetModeAttribMESA
;
529 drv
->API
.GetScreensMESA
= _eglGetScreensMESA
;
530 drv
->API
.CreateScreenSurfaceMESA
= _eglCreateScreenSurfaceMESA
;
531 drv
->API
.ShowScreenSurfaceMESA
= _eglShowScreenSurfaceMESA
;
532 drv
->API
.ScreenPositionMESA
= _eglScreenPositionMESA
;
533 drv
->API
.QueryScreenMESA
= _eglQueryScreenMESA
;
534 drv
->API
.QueryScreenSurfaceMESA
= _eglQueryScreenSurfaceMESA
;
535 drv
->API
.QueryScreenModeMESA
= _eglQueryScreenModeMESA
;
536 drv
->API
.QueryModeStringMESA
= _eglQueryModeStringMESA
;
537 #endif /* EGL_MESA_screen_surface */
539 #ifdef EGL_VERSION_1_2
540 drv
->API
.CreatePbufferFromClientBuffer
= _eglCreatePbufferFromClientBuffer
;
541 #endif /* EGL_VERSION_1_2 */
543 #ifdef EGL_KHR_image_base
544 drv
->API
.CreateImageKHR
= _eglCreateImageKHR
;
545 drv
->API
.DestroyImageKHR
= _eglDestroyImageKHR
;
546 #endif /* EGL_KHR_image_base */
551 * Invoke a callback function on each EGL search path.
553 * The first argument of the callback function is the name of the search path.
554 * The second argument is the length of the name.
557 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
560 const char *search_path
= _eglGetSearchPath();
561 _eglPreloadForEach(search_path
, callback
, callback_data
);