2 * Functions for choosing and opening/loading device drivers.
10 #include "eglconfig.h"
11 #include "eglcontext.h"
12 #include "egldefines.h"
13 #include "egldisplay.h"
14 #include "egldriver.h"
15 #include "eglglobals.h"
19 #include "eglscreen.h"
20 #include "eglstring.h"
21 #include "eglsurface.h"
24 #if defined(_EGL_PLATFORM_POSIX)
26 #include <sys/types.h>
33 * Wrappers for dlopen/dlclose()
35 #if defined(_EGL_PLATFORM_WINDOWS)
38 /* XXX Need to decide how to do dynamic name lookup on Windows */
39 static const char DefaultDriverName
[] = "TBD";
41 typedef HMODULE lib_handle
;
44 open_library(const char *filename
)
46 return LoadLibrary(filename
);
50 close_library(HMODULE lib
)
63 #elif defined(_EGL_PLATFORM_POSIX)
66 static const char DefaultDriverName
[] = "egl_glx";
68 typedef void * lib_handle
;
71 open_library(const char *filename
)
73 return dlopen(filename
, RTLD_LAZY
);
77 close_library(void *lib
)
90 #else /* _EGL_PLATFORM_NO_OS */
93 static const char DefaultDriverName
[] = "builtin";
95 typedef void *lib_handle
;
98 open_library(const char *filename
)
100 return (void *) filename
;
104 close_library(void *lib
)
119 #define NUM_PROBE_CACHE_SLOTS 8
121 EGLint keys
[NUM_PROBE_CACHE_SLOTS
];
122 const void *values
[NUM_PROBE_CACHE_SLOTS
];
127 * Open the named driver and find its bootstrap function: _eglMain().
130 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
133 _EGLMain_t mainFunc
= NULL
;
134 const char *error
= "unknown error";
138 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
139 lib
= open_library(driverPath
);
141 #if defined(_EGL_PLATFORM_WINDOWS)
144 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
145 #elif defined(_EGL_PLATFORM_POSIX)
147 mainFunc
= (_EGLMain_t
) dlsym(lib
, "_eglMain");
154 #else /* _EGL_PLATFORM_NO_OS */
155 /* must be the default driver name */
156 if (strcmp(driverPath
, DefaultDriverName
) == 0)
157 mainFunc
= (_EGLMain_t
) _eglMain
;
159 error
= "not builtin driver";
163 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
165 if (!getenv("EGL_DRIVER"))
166 _eglLog(_EGL_WARNING
,
167 "The driver can be overridden by setting EGL_DRIVER");
172 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
185 * Load the named driver.
188 _eglLoadDriver(const char *path
, const char *args
)
192 _EGLDriver
*drv
= NULL
;
194 mainFunc
= _eglOpenLibrary(path
, &lib
);
198 drv
= mainFunc(args
);
206 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", path
);
207 drv
->Name
= "UNNAMED";
210 drv
->Path
= _eglstrdup(path
);
211 drv
->Args
= (args
) ? _eglstrdup(args
) : NULL
;
212 if (!drv
->Path
|| (args
&& !drv
->Args
)) {
214 free((char *) drv
->Path
);
216 free((char *) drv
->Args
);
223 drv
->LibHandle
= lib
;
230 * Match a display to a preloaded driver.
232 * The matching is done by finding the driver with the highest score.
235 _eglMatchDriver(_EGLDisplay
*dpy
)
237 _EGLDriver
*best_drv
= NULL
;
238 EGLint best_score
= -1, i
;
240 for (i
= 0; i
< _eglGlobal
.NumDrivers
; i
++) {
241 _EGLDriver
*drv
= _eglGlobal
.Drivers
[i
];
244 score
= (drv
->Probe
) ? drv
->Probe(drv
, dpy
) : 0;
245 if (score
> best_score
) {
247 _eglLog(_EGL_DEBUG
, "driver %s has higher score than %s",
248 drv
->Name
, best_drv
->Name
);
264 * A preload function for use with _eglPreloadForEach. The preload data is the
265 * filename of the driver. This function stops on the first valid driver.
268 _eglPreloadFile(const char *dir
, size_t len
, void *preload_data
)
272 const char *filename
= (const char *) preload_data
;
273 size_t flen
= strlen(filename
);
275 /* make a full path */
276 if (len
+ flen
+ 2 > sizeof(path
))
279 memcpy(path
, dir
, len
);
282 memcpy(path
+ len
, filename
, flen
);
286 drv
= _eglLoadDriver(path
, NULL
);
287 /* fix the path and load again */
288 if (!drv
&& library_suffix()) {
289 const char *suffix
= library_suffix();
290 size_t slen
= strlen(suffix
);
292 EGLBoolean need_suffix
;
294 p
= filename
+ flen
- slen
;
295 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
296 if (need_suffix
&& len
+ slen
+ 1 <= sizeof(path
)) {
297 strcpy(path
+ len
, suffix
);
298 drv
= _eglLoadDriver(path
, NULL
);
304 /* remember the driver and stop */
305 _eglGlobal
.Drivers
[_eglGlobal
.NumDrivers
++] = drv
;
311 * A preload function for use with _eglPreloadForEach. The preload data is the
312 * pattern (prefix) of the files to look for.
315 _eglPreloadPattern(const char *dir
, size_t len
, void *preload_data
)
317 #if defined(_EGL_PLATFORM_POSIX)
318 const char *prefix
, *suffix
;
319 size_t prefix_len
, suffix_len
;
321 struct dirent
*dirent
;
324 if (len
+ 2 > sizeof(path
))
327 memcpy(path
, dir
, len
);
332 dirp
= opendir(path
);
336 prefix
= (const char *) preload_data
;
337 prefix_len
= strlen(prefix
);
338 suffix
= library_suffix();
339 suffix_len
= (suffix
) ? strlen(suffix
) : 0;
341 while ((dirent
= readdir(dirp
))) {
343 size_t dirent_len
= strlen(dirent
->d_name
);
346 /* match the prefix */
347 if (strncmp(dirent
->d_name
, prefix
, prefix_len
) != 0)
349 /* match the suffix */
350 p
= dirent
->d_name
+ dirent_len
- suffix_len
;
351 if (p
< dirent
->d_name
|| strcmp(p
, suffix
) != 0)
354 /* make a full path and load the driver */
355 if (len
+ dirent_len
+ 1 <= sizeof(path
)) {
356 strcpy(path
+ len
, dirent
->d_name
);
357 drv
= _eglLoadDriver(path
, NULL
);
359 _eglGlobal
.Drivers
[_eglGlobal
.NumDrivers
++] = drv
;
366 #else /* _EGL_PLATFORM_POSIX */
367 /* stop immediately */
374 * Run the preload function on each driver directory and return the number of
377 * The process may end prematurely if the callback function returns false.
380 _eglPreloadForEach(const char *search_path
,
381 EGLBoolean (*preload
)(const char *, size_t, void *),
384 const char *cur
, *next
;
386 EGLint num_drivers
= _eglGlobal
.NumDrivers
;
390 next
= strchr(cur
, ':');
391 len
= (next
) ? next
- cur
: strlen(cur
);
393 if (!preload(cur
, len
, preload_data
))
396 cur
= (next
) ? next
+ 1 : NULL
;
399 return (_eglGlobal
.NumDrivers
- num_drivers
);
404 * Return a list of colon-separated driver directories.
407 _eglGetSearchPath(void)
409 static const char *search_path
;
411 #if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS)
413 static char buffer
[1024];
417 p
= getenv("EGL_DRIVERS_PATH");
419 ret
= snprintf(buffer
, sizeof(buffer
),
420 "%s:%s", p
, _EGL_DRIVER_SEARCH_DIR
);
421 if (ret
> 0 && ret
< sizeof(buffer
))
422 search_path
= buffer
;
426 search_path
= _EGL_DRIVER_SEARCH_DIR
;
436 * Preload a user driver.
438 * A user driver can be specified by EGL_DRIVER.
441 _eglPreloadUserDriver(void)
443 #if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS)
444 const char *search_path
= _eglGetSearchPath();
447 env
= getenv("EGL_DRIVER");
448 #if defined(_EGL_PLATFORM_POSIX)
449 if (env
&& strchr(env
, '/'))
455 if (!_eglPreloadForEach(search_path
, _eglPreloadFile
, (void *) env
)) {
456 _eglLog(_EGL_WARNING
, "EGL_DRIVER is set to an invalid driver");
461 #else /* _EGL_PLATFORM_POSIX || _EGL_PLATFORM_WINDOWS */
468 * Preload display drivers.
470 * Display drivers are a set of drivers that support a certain display system.
471 * The display system may be specified by EGL_DISPLAY.
473 * FIXME This makes libEGL a memory hog if an user driver is not specified and
474 * there are many display drivers.
477 _eglPreloadDisplayDrivers(void)
479 #if defined(_EGL_PLATFORM_POSIX)
484 dpy
= getenv("EGL_DISPLAY");
486 dpy
= _EGL_DEFAULT_DISPLAY
;
490 ret
= snprintf(prefix
, sizeof(prefix
), "egl_%s_", dpy
);
491 if (ret
< 0 || ret
>= sizeof(prefix
))
494 return (_eglPreloadForEach(_eglGetSearchPath(),
495 _eglPreloadPattern
, (void *) prefix
) > 0);
496 #else /* _EGL_PLATFORM_POSIX */
503 * Preload the default driver.
506 _eglPreloadDefaultDriver(void)
508 return (_eglPreloadForEach(_eglGetSearchPath(),
509 _eglPreloadFile
, (void *) DefaultDriverName
) > 0);
516 * This function loads the driver modules and creates the corresponding
517 * _EGLDriver objects.
520 _eglPreloadDrivers(void)
524 /* already preloaded */
525 if (_eglGlobal
.NumDrivers
)
528 loaded
= (_eglPreloadUserDriver() ||
529 _eglPreloadDisplayDrivers() ||
530 _eglPreloadDefaultDriver());
537 * Unload preloaded drivers.
540 _eglUnloadDrivers(void)
543 for (i
= 0; i
< _eglGlobal
.NumDrivers
; i
++) {
544 _EGLDriver
*drv
= _eglGlobal
.Drivers
[i
];
545 lib_handle handle
= drv
->LibHandle
;
548 free((char *) drv
->Path
);
550 free((char *) drv
->Args
);
557 close_library(handle
);
558 _eglGlobal
.Drivers
[i
] = NULL
;
561 _eglGlobal
.NumDrivers
= 0;
566 * Plug all the available fallback routines into the given driver's
570 _eglInitDriverFallbacks(_EGLDriver
*drv
)
572 /* If a pointer is set to NULL, then the device driver _really_ has
575 drv
->API
.Initialize
= NULL
;
576 drv
->API
.Terminate
= NULL
;
578 drv
->API
.GetConfigs
= _eglGetConfigs
;
579 drv
->API
.ChooseConfig
= _eglChooseConfig
;
580 drv
->API
.GetConfigAttrib
= _eglGetConfigAttrib
;
582 drv
->API
.CreateContext
= _eglCreateContext
;
583 drv
->API
.DestroyContext
= _eglDestroyContext
;
584 drv
->API
.MakeCurrent
= _eglMakeCurrent
;
585 drv
->API
.QueryContext
= _eglQueryContext
;
587 drv
->API
.CreateWindowSurface
= _eglCreateWindowSurface
;
588 drv
->API
.CreatePixmapSurface
= _eglCreatePixmapSurface
;
589 drv
->API
.CreatePbufferSurface
= _eglCreatePbufferSurface
;
590 drv
->API
.DestroySurface
= _eglDestroySurface
;
591 drv
->API
.QuerySurface
= _eglQuerySurface
;
592 drv
->API
.SurfaceAttrib
= _eglSurfaceAttrib
;
593 drv
->API
.BindTexImage
= _eglBindTexImage
;
594 drv
->API
.ReleaseTexImage
= _eglReleaseTexImage
;
595 drv
->API
.SwapInterval
= _eglSwapInterval
;
596 drv
->API
.SwapBuffers
= _eglSwapBuffers
;
597 drv
->API
.CopyBuffers
= _eglCopyBuffers
;
599 drv
->API
.QueryString
= _eglQueryString
;
600 drv
->API
.WaitClient
= _eglWaitClient
;
601 drv
->API
.WaitNative
= _eglWaitNative
;
603 #ifdef EGL_MESA_screen_surface
604 drv
->API
.ChooseModeMESA
= _eglChooseModeMESA
;
605 drv
->API
.GetModesMESA
= _eglGetModesMESA
;
606 drv
->API
.GetModeAttribMESA
= _eglGetModeAttribMESA
;
607 drv
->API
.GetScreensMESA
= _eglGetScreensMESA
;
608 drv
->API
.CreateScreenSurfaceMESA
= _eglCreateScreenSurfaceMESA
;
609 drv
->API
.ShowScreenSurfaceMESA
= _eglShowScreenSurfaceMESA
;
610 drv
->API
.ScreenPositionMESA
= _eglScreenPositionMESA
;
611 drv
->API
.QueryScreenMESA
= _eglQueryScreenMESA
;
612 drv
->API
.QueryScreenSurfaceMESA
= _eglQueryScreenSurfaceMESA
;
613 drv
->API
.QueryScreenModeMESA
= _eglQueryScreenModeMESA
;
614 drv
->API
.QueryModeStringMESA
= _eglQueryModeStringMESA
;
615 #endif /* EGL_MESA_screen_surface */
617 #ifdef EGL_VERSION_1_2
618 drv
->API
.CreatePbufferFromClientBuffer
= _eglCreatePbufferFromClientBuffer
;
619 #endif /* EGL_VERSION_1_2 */
621 #ifdef EGL_KHR_image_base
622 drv
->API
.CreateImageKHR
= _eglCreateImageKHR
;
623 drv
->API
.DestroyImageKHR
= _eglDestroyImageKHR
;
624 #endif /* EGL_KHR_image_base */
629 * Set the probe cache at the given key.
631 * A key, instead of a _EGLDriver, is used to allow the probe cache to be share
632 * by multiple drivers.
635 _eglSetProbeCache(EGLint key
, const void *val
)
639 for (idx
= 0; idx
< NUM_PROBE_CACHE_SLOTS
; idx
++) {
640 if (!_eglProbeCache
.keys
[idx
] || _eglProbeCache
.keys
[idx
] == key
)
644 assert(idx
< NUM_PROBE_CACHE_SLOTS
);
646 _eglProbeCache
.keys
[idx
] = key
;
647 _eglProbeCache
.values
[idx
] = val
;
652 * Return the probe cache at the given key.
655 _eglGetProbeCache(EGLint key
)
659 for (idx
= 0; idx
< NUM_PROBE_CACHE_SLOTS
; idx
++) {
660 if (!_eglProbeCache
.keys
[idx
] || _eglProbeCache
.keys
[idx
] == key
)
664 return (idx
< NUM_PROBE_CACHE_SLOTS
&& _eglProbeCache
.keys
[idx
] == key
) ?
665 _eglProbeCache
.values
[idx
] : NULL
;