1 /**************************************************************************
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
32 * Functions for choosing and opening/loading device drivers.
41 #include "eglstring.h"
42 #include "egldefines.h"
43 #include "egldisplay.h"
44 #include "egldriver.h"
48 #if defined(_EGL_OS_UNIX)
50 #include <sys/types.h>
55 #ifdef _EGL_BUILT_IN_DRIVER_HAIKU
56 _EGLDriver
* _eglBuiltInDriverHaiku(const char* args
);
59 typedef struct _egl_module
{
66 static _EGLMutex _eglModuleMutex
= _EGL_MUTEX_INITIALIZER
;
67 static _EGLArray
*_eglModules
;
72 } _eglBuiltInDrivers
[] = {
73 #ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
74 { "egl_gallium", _eglBuiltInDriverGALLIUM
},
76 #ifdef _EGL_BUILT_IN_DRIVER_DRI2
77 { "egl_dri2", _eglBuiltInDriverDRI2
},
79 #ifdef _EGL_BUILT_IN_DRIVER_HAIKU
80 { "egl_haiku", _eglBuiltInDriverHaiku
},
86 * Wrappers for dlopen/dlclose()
88 #if defined(_EGL_OS_WINDOWS)
91 typedef HMODULE lib_handle
;
94 open_library(const char *filename
)
96 return LoadLibrary(filename
);
100 close_library(HMODULE lib
)
113 #elif defined(_EGL_OS_UNIX)
116 typedef void * lib_handle
;
119 open_library(const char *filename
)
121 return dlopen(filename
, RTLD_LAZY
);
125 close_library(void *lib
)
142 * Open the named driver and find its bootstrap function: _eglMain().
145 _eglOpenLibrary(const char *driverPath
, lib_handle
*handle
)
148 _EGLMain_t mainFunc
= NULL
;
149 const char *error
= "unknown error";
153 _eglLog(_EGL_DEBUG
, "dlopen(%s)", driverPath
);
154 lib
= open_library(driverPath
);
156 #if defined(_EGL_OS_WINDOWS)
159 mainFunc
= (_EGLMain_t
) GetProcAddress(lib
, "_eglMain");
160 #elif defined(_EGL_OS_UNIX)
166 /* direct cast gives a warning when compiled with -pedantic */
167 tmp
.ptr
= dlsym(lib
, "_eglMain");
178 _eglLog(_EGL_WARNING
, "Could not open driver %s (%s)",
184 _eglLog(_EGL_WARNING
, "_eglMain not found in %s (%s)",
197 * Load a module and create the driver object.
200 _eglLoadModule(_EGLModule
*mod
)
210 lib
= (lib_handle
) NULL
;
211 mainFunc
= mod
->BuiltIn
;
214 mainFunc
= _eglOpenLibrary(mod
->Path
, &lib
);
219 drv
= mainFunc(NULL
);
227 _eglLog(_EGL_WARNING
, "Driver loaded from %s has no name", mod
->Path
);
228 drv
->Name
= "UNNAMED";
231 mod
->Handle
= (void *) lib
;
242 _eglUnloadModule(_EGLModule
*mod
)
244 #if defined(_EGL_OS_UNIX)
245 /* destroy the driver */
246 if (mod
->Driver
&& mod
->Driver
->Unload
)
247 mod
->Driver
->Unload(mod
->Driver
);
250 * XXX At this point (atexit), the module might be the last reference to
251 * libEGL. Closing the module might unmap libEGL and give problems.
255 close_library(mod
->Handle
);
257 #elif defined(_EGL_OS_WINDOWS)
258 /* XXX Windows unloads DLLs before atexit */
267 * Add a module to the module array.
270 _eglAddModule(const char *path
)
276 _eglModules
= _eglCreateArray("Module", 8);
281 /* find duplicates */
282 for (i
= 0; i
< _eglModules
->Size
; i
++) {
283 mod
= _eglModules
->Elements
[i
];
284 if (strcmp(mod
->Path
, path
) == 0)
288 /* allocate a new one */
289 mod
= calloc(1, sizeof(*mod
));
291 mod
->Path
= _eglstrdup(path
);
298 _eglAppendArray(_eglModules
, (void *) mod
);
299 _eglLog(_EGL_DEBUG
, "added %s to module array", mod
->Path
);
310 _eglFreeModule(void *module
)
312 _EGLModule
*mod
= (_EGLModule
*) module
;
314 _eglUnloadModule(mod
);
321 * A loader function for use with _eglPreloadForEach. The loader data is the
322 * filename of the driver. This function stops on the first valid driver.
325 _eglLoaderFile(const char *dir
, size_t len
, void *loader_data
)
328 const char *filename
= (const char *) loader_data
;
329 size_t flen
= strlen(filename
);
331 /* make a full path */
332 if (len
+ flen
+ 2 > sizeof(path
))
335 memcpy(path
, dir
, len
);
338 memcpy(path
+ len
, filename
, flen
);
342 if (library_suffix()) {
343 const char *suffix
= library_suffix();
344 size_t slen
= strlen(suffix
);
346 EGLBoolean need_suffix
;
348 p
= filename
+ flen
- slen
;
349 need_suffix
= (p
< filename
|| strcmp(p
, suffix
) != 0);
352 if (len
+ slen
+ 1 > sizeof(path
))
354 strcpy(path
+ len
, suffix
);
358 #if defined(_EGL_OS_UNIX)
359 /* check if the file exists */
360 if (access(path
, F_OK
))
371 * Run the callback function on each driver directory.
373 * The process may end prematurely if the callback function returns false.
376 _eglPreloadForEach(const char *search_path
,
377 EGLBoolean (*loader
)(const char *, size_t, void *),
380 const char *cur
, *next
;
385 next
= strchr(cur
, ':');
386 len
= (next
) ? next
- cur
: strlen(cur
);
388 if (!loader(cur
, len
, loader_data
))
391 cur
= (next
) ? next
+ 1 : NULL
;
397 * Return a list of colon-separated driver directories.
400 _eglGetSearchPath(void)
402 static char search_path
[1024];
404 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
405 if (search_path
[0] == '\0') {
406 char *buf
= search_path
;
407 size_t len
= sizeof(search_path
);
412 #if defined(_EGL_OS_UNIX)
413 use_env
= (geteuid() == getuid() && getegid() == getgid());
423 /* extract the dirname from EGL_DRIVER */
424 p
= getenv("EGL_DRIVER");
425 if (p
&& strchr(p
, dir_sep
)) {
426 ret
= _eglsnprintf(buf
, len
, "%s", p
);
427 if (ret
> 0 && ret
< len
) {
428 p
= strrchr(buf
, dir_sep
);
436 /* append EGL_DRIVERS_PATH */
437 p
= getenv("EGL_DRIVERS_PATH");
439 ret
= _eglsnprintf(buf
, len
, "%s:", p
);
440 if (ret
> 0 && ret
< len
) {
448 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
451 ret
= _eglsnprintf(buf
, len
, "%s", _EGL_DRIVER_SEARCH_DIR
);
452 if (ret
< 0 || ret
>= len
)
453 search_path
[0] = '\0';
455 _eglLog(_EGL_DEBUG
, "EGL search path is %s", search_path
);
457 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
464 * Add the user driver to the module array.
466 * The user driver is specified by EGL_DRIVER.
469 _eglAddUserDriver(void)
471 const char *search_path
= _eglGetSearchPath();
475 env
= getenv("EGL_DRIVER");
476 #if defined(_EGL_OS_UNIX)
477 if (env
&& strchr(env
, '/')) {
479 if ((geteuid() != getuid() || getegid() != getgid())) {
481 "ignore EGL_DRIVER for setuid/setgid binaries");
486 char *suffix
= strchr(env
, '.');
487 name_len
= (suffix
) ? suffix
- env
: strlen(env
);
491 name_len
= strlen(env
);
492 #endif /* _EGL_OS_UNIX */
495 * Try built-in drivers first if we know the driver name. This makes sure
496 * we do not load the outdated external driver that is still on the
503 for (i
= 0; _eglBuiltInDrivers
[i
].name
; i
++) {
504 if (strlen(_eglBuiltInDrivers
[i
].name
) == name_len
&&
505 !strncmp(_eglBuiltInDrivers
[i
].name
, env
, name_len
)) {
506 mod
= _eglAddModule(env
);
508 mod
->BuiltIn
= _eglBuiltInDrivers
[i
].main
;
515 /* otherwise, treat env as a path */
517 _eglPreloadForEach(search_path
, _eglLoaderFile
, (void *) env
);
527 * Add built-in drivers to the module array.
530 _eglAddBuiltInDrivers(void)
535 for (i
= 0; _eglBuiltInDrivers
[i
].name
; i
++) {
536 mod
= _eglAddModule(_eglBuiltInDrivers
[i
].name
);
538 mod
->BuiltIn
= _eglBuiltInDrivers
[i
].main
;
544 * Add drivers to the module array. Drivers will be loaded as they are matched
553 if (!_eglAddUserDriver()) {
555 * Add other drivers only when EGL_DRIVER is not set. The order here
556 * decides the priorities.
558 _eglAddBuiltInDrivers();
561 return (_eglModules
!= NULL
);
566 * A helper function for _eglMatchDriver. It finds the first driver that can
567 * initialize the display and return.
570 _eglMatchAndInitialize(_EGLDisplay
*dpy
)
572 _EGLDriver
*drv
= NULL
;
575 if (!_eglAddDrivers()) {
576 _eglLog(_EGL_WARNING
, "failed to find any driver");
582 /* no re-matching? */
583 if (!drv
->API
.Initialize(drv
, dpy
))
588 while (i
< _eglModules
->Size
) {
589 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
591 if (!_eglLoadModule(mod
)) {
592 /* remove invalid modules */
593 _eglEraseArray(_eglModules
, i
, _eglFreeModule
);
597 if (mod
->Driver
->API
.Initialize(mod
->Driver
, dpy
)) {
611 * Match a display to a driver. The display is initialized unless test_only is
612 * true. The matching is done by finding the first driver that can initialize
616 _eglMatchDriver(_EGLDisplay
*dpy
, EGLBoolean test_only
)
618 _EGLDriver
*best_drv
;
620 assert(!dpy
->Initialized
);
622 _eglLockMutex(&_eglModuleMutex
);
625 dpy
->Options
.TestOnly
= test_only
;
626 dpy
->Options
.UseFallback
= EGL_FALSE
;
628 best_drv
= _eglMatchAndInitialize(dpy
);
630 dpy
->Options
.UseFallback
= EGL_TRUE
;
631 best_drv
= _eglMatchAndInitialize(dpy
);
634 _eglUnlockMutex(&_eglModuleMutex
);
637 _eglLog(_EGL_DEBUG
, "the best driver is %s%s",
638 best_drv
->Name
, (test_only
) ? " (test only) " : "");
640 dpy
->Driver
= best_drv
;
641 dpy
->Initialized
= EGL_TRUE
;
649 __eglMustCastToProperFunctionPointerType
650 _eglGetDriverProc(const char *procname
)
653 _EGLProc proc
= NULL
;
656 /* load the driver for the default display */
657 EGLDisplay egldpy
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
658 _EGLDisplay
*dpy
= _eglLookupDisplay(egldpy
);
659 if (!dpy
|| !_eglMatchDriver(dpy
, EGL_TRUE
))
663 for (i
= 0; i
< _eglModules
->Size
; i
++) {
664 _EGLModule
*mod
= (_EGLModule
*) _eglModules
->Elements
[i
];
668 proc
= mod
->Driver
->API
.GetProcAddress(mod
->Driver
, procname
);
678 * Unload all drivers.
681 _eglUnloadDrivers(void)
683 /* this is called at atexit time */
685 _eglDestroyArray(_eglModules
, _eglFreeModule
);
692 * Invoke a callback function on each EGL search path.
694 * The first argument of the callback function is the name of the search path.
695 * The second argument is the length of the name.
698 _eglSearchPathForEach(EGLBoolean (*callback
)(const char *, size_t, void *),
701 const char *search_path
= _eglGetSearchPath();
702 _eglPreloadForEach(search_path
, callback
, callback_data
);