egl: remove egl_gallium from the loader
[mesa.git] / src / egl / main / egldriver.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
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:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
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.
27 *
28 **************************************************************************/
29
30
31 /**
32 * Functions for choosing and opening/loading device drivers.
33 */
34
35
36 #include <assert.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #include "eglstring.h"
42 #include "egldefines.h"
43 #include "egldisplay.h"
44 #include "egldriver.h"
45 #include "egllog.h"
46 #include "eglmutex.h"
47
48 #if defined(_EGL_OS_UNIX)
49 #include <dlfcn.h>
50 #include <sys/types.h>
51 #include <dirent.h>
52 #include <unistd.h>
53 #endif
54
55
56 typedef struct _egl_module {
57 char *Path;
58 _EGLMain_t BuiltIn;
59 void *Handle;
60 _EGLDriver *Driver;
61 } _EGLModule;
62
63 static _EGLMutex _eglModuleMutex = _EGL_MUTEX_INITIALIZER;
64 static _EGLArray *_eglModules;
65
66 const struct {
67 const char *name;
68 _EGLMain_t main;
69 } _eglBuiltInDrivers[] = {
70 #ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
71 { "egl_gallium", _eglBuiltInDriverGALLIUM },
72 #endif
73 #ifdef _EGL_BUILT_IN_DRIVER_DRI2
74 { "egl_dri2", _eglBuiltInDriverDRI2 },
75 #endif
76 { NULL, NULL }
77 };
78
79 /**
80 * Wrappers for dlopen/dlclose()
81 */
82 #if defined(_EGL_OS_WINDOWS)
83
84
85 typedef HMODULE lib_handle;
86
87 static HMODULE
88 open_library(const char *filename)
89 {
90 return LoadLibrary(filename);
91 }
92
93 static void
94 close_library(HMODULE lib)
95 {
96 FreeLibrary(lib);
97 }
98
99
100 static const char *
101 library_suffix(void)
102 {
103 return ".dll";
104 }
105
106
107 #elif defined(_EGL_OS_UNIX)
108
109
110 typedef void * lib_handle;
111
112 static void *
113 open_library(const char *filename)
114 {
115 return dlopen(filename, RTLD_LAZY);
116 }
117
118 static void
119 close_library(void *lib)
120 {
121 dlclose(lib);
122 }
123
124
125 static const char *
126 library_suffix(void)
127 {
128 return ".so";
129 }
130
131
132 #endif
133
134
135 /**
136 * Open the named driver and find its bootstrap function: _eglMain().
137 */
138 static _EGLMain_t
139 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
140 {
141 lib_handle lib;
142 _EGLMain_t mainFunc = NULL;
143 const char *error = "unknown error";
144
145 assert(driverPath);
146
147 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
148 lib = open_library(driverPath);
149
150 #if defined(_EGL_OS_WINDOWS)
151 /* XXX untested */
152 if (lib)
153 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
154 #elif defined(_EGL_OS_UNIX)
155 if (lib) {
156 union {
157 _EGLMain_t func;
158 void *ptr;
159 } tmp = { NULL };
160 /* direct cast gives a warning when compiled with -pedantic */
161 tmp.ptr = dlsym(lib, "_eglMain");
162 mainFunc = tmp.func;
163 if (!mainFunc)
164 error = dlerror();
165 }
166 else {
167 error = dlerror();
168 }
169 #endif
170
171 if (!lib) {
172 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
173 driverPath, error);
174 return NULL;
175 }
176
177 if (!mainFunc) {
178 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
179 driverPath, error);
180 if (lib)
181 close_library(lib);
182 return NULL;
183 }
184
185 *handle = lib;
186 return mainFunc;
187 }
188
189
190 /**
191 * Load a module and create the driver object.
192 */
193 static EGLBoolean
194 _eglLoadModule(_EGLModule *mod)
195 {
196 _EGLMain_t mainFunc;
197 lib_handle lib;
198 _EGLDriver *drv;
199
200 if (mod->Driver)
201 return EGL_TRUE;
202
203 if (mod->BuiltIn) {
204 lib = (lib_handle) NULL;
205 mainFunc = mod->BuiltIn;
206 }
207 else {
208 mainFunc = _eglOpenLibrary(mod->Path, &lib);
209 if (!mainFunc)
210 return EGL_FALSE;
211 }
212
213 drv = mainFunc(NULL);
214 if (!drv) {
215 if (lib)
216 close_library(lib);
217 return EGL_FALSE;
218 }
219
220 if (!drv->Name) {
221 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
222 drv->Name = "UNNAMED";
223 }
224
225 mod->Handle = (void *) lib;
226 mod->Driver = drv;
227
228 return EGL_TRUE;
229 }
230
231
232 /**
233 * Unload a module.
234 */
235 static void
236 _eglUnloadModule(_EGLModule *mod)
237 {
238 #if defined(_EGL_OS_UNIX)
239 /* destroy the driver */
240 if (mod->Driver && mod->Driver->Unload)
241 mod->Driver->Unload(mod->Driver);
242
243 /*
244 * XXX At this point (atexit), the module might be the last reference to
245 * libEGL. Closing the module might unmap libEGL and give problems.
246 */
247 #if 0
248 if (mod->Handle)
249 close_library(mod->Handle);
250 #endif
251 #elif defined(_EGL_OS_WINDOWS)
252 /* XXX Windows unloads DLLs before atexit */
253 #endif
254
255 mod->Driver = NULL;
256 mod->Handle = NULL;
257 }
258
259
260 /**
261 * Add a module to the module array.
262 */
263 static _EGLModule *
264 _eglAddModule(const char *path)
265 {
266 _EGLModule *mod;
267 EGLint i;
268
269 if (!_eglModules) {
270 _eglModules = _eglCreateArray("Module", 8);
271 if (!_eglModules)
272 return NULL;
273 }
274
275 /* find duplicates */
276 for (i = 0; i < _eglModules->Size; i++) {
277 mod = _eglModules->Elements[i];
278 if (strcmp(mod->Path, path) == 0)
279 return mod;
280 }
281
282 /* allocate a new one */
283 mod = calloc(1, sizeof(*mod));
284 if (mod) {
285 mod->Path = _eglstrdup(path);
286 if (!mod->Path) {
287 free(mod);
288 mod = NULL;
289 }
290 }
291 if (mod) {
292 _eglAppendArray(_eglModules, (void *) mod);
293 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
294 }
295
296 return mod;
297 }
298
299
300 /**
301 * Free a module.
302 */
303 static void
304 _eglFreeModule(void *module)
305 {
306 _EGLModule *mod = (_EGLModule *) module;
307
308 _eglUnloadModule(mod);
309 free(mod->Path);
310 free(mod);
311 }
312
313
314 /**
315 * A loader function for use with _eglPreloadForEach. The loader data is the
316 * filename of the driver. This function stops on the first valid driver.
317 */
318 static EGLBoolean
319 _eglLoaderFile(const char *dir, size_t len, void *loader_data)
320 {
321 char path[1024];
322 const char *filename = (const char *) loader_data;
323 size_t flen = strlen(filename);
324
325 /* make a full path */
326 if (len + flen + 2 > sizeof(path))
327 return EGL_TRUE;
328 if (len) {
329 memcpy(path, dir, len);
330 path[len++] = '/';
331 }
332 memcpy(path + len, filename, flen);
333 len += flen;
334 path[len] = '\0';
335
336 if (library_suffix()) {
337 const char *suffix = library_suffix();
338 size_t slen = strlen(suffix);
339 const char *p;
340 EGLBoolean need_suffix;
341
342 p = filename + flen - slen;
343 need_suffix = (p < filename || strcmp(p, suffix) != 0);
344 if (need_suffix) {
345 /* overflow */
346 if (len + slen + 1 > sizeof(path))
347 return EGL_TRUE;
348 strcpy(path + len, suffix);
349 }
350 }
351
352 #if defined(_EGL_OS_UNIX)
353 /* check if the file exists */
354 if (access(path, F_OK))
355 return EGL_TRUE;
356 #endif
357
358 _eglAddModule(path);
359
360 return EGL_TRUE;
361 }
362
363
364 /**
365 * Run the callback function on each driver directory.
366 *
367 * The process may end prematurely if the callback function returns false.
368 */
369 static void
370 _eglPreloadForEach(const char *search_path,
371 EGLBoolean (*loader)(const char *, size_t, void *),
372 void *loader_data)
373 {
374 const char *cur, *next;
375 size_t len;
376
377 cur = search_path;
378 while (cur) {
379 next = strchr(cur, ':');
380 len = (next) ? next - cur : strlen(cur);
381
382 if (!loader(cur, len, loader_data))
383 break;
384
385 cur = (next) ? next + 1 : NULL;
386 }
387 }
388
389
390 /**
391 * Return a list of colon-separated driver directories.
392 */
393 static const char *
394 _eglGetSearchPath(void)
395 {
396 static char search_path[1024];
397
398 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
399 if (search_path[0] == '\0') {
400 char *buf = search_path;
401 size_t len = sizeof(search_path);
402 EGLBoolean use_env;
403 char dir_sep;
404 int ret;
405
406 #if defined(_EGL_OS_UNIX)
407 use_env = (geteuid() == getuid() && getegid() == getgid());
408 dir_sep = '/';
409 #else
410 use_env = EGL_TRUE;
411 dir_sep = '\\';
412 #endif
413
414 if (use_env) {
415 char *p;
416
417 /* extract the dirname from EGL_DRIVER */
418 p = getenv("EGL_DRIVER");
419 if (p && strchr(p, dir_sep)) {
420 ret = _eglsnprintf(buf, len, "%s", p);
421 if (ret > 0 && ret < len) {
422 p = strrchr(buf, dir_sep);
423 *p++ = ':';
424
425 len -= p - buf;
426 buf = p;
427 }
428 }
429
430 /* append EGL_DRIVERS_PATH */
431 p = getenv("EGL_DRIVERS_PATH");
432 if (p) {
433 ret = _eglsnprintf(buf, len, "%s:", p);
434 if (ret > 0 && ret < len) {
435 buf += ret;
436 len -= ret;
437 }
438 }
439 }
440 else {
441 _eglLog(_EGL_DEBUG,
442 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
443 }
444
445 ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR);
446 if (ret < 0 || ret >= len)
447 search_path[0] = '\0';
448
449 _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path);
450 }
451 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
452
453 return search_path;
454 }
455
456
457 /**
458 * Add the user driver to the module array.
459 *
460 * The user driver is specified by EGL_DRIVER.
461 */
462 static EGLBoolean
463 _eglAddUserDriver(void)
464 {
465 const char *search_path = _eglGetSearchPath();
466 char *env;
467 size_t name_len = 0;
468
469 env = getenv("EGL_DRIVER");
470 #if defined(_EGL_OS_UNIX)
471 if (env && strchr(env, '/')) {
472 search_path = "";
473 if ((geteuid() != getuid() || getegid() != getgid())) {
474 _eglLog(_EGL_DEBUG,
475 "ignore EGL_DRIVER for setuid/setgid binaries");
476 env = NULL;
477 }
478 }
479 else if (env) {
480 char *suffix = strchr(env, '.');
481 name_len = (suffix) ? suffix - env : strlen(env);
482 }
483 #else
484 if (env)
485 name_len = strlen(env);
486 #endif /* _EGL_OS_UNIX */
487
488 /*
489 * Try built-in drivers first if we know the driver name. This makes sure
490 * we do not load the outdated external driver that is still on the
491 * filesystem.
492 */
493 if (name_len) {
494 _EGLModule *mod;
495 EGLint i;
496
497 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
498 if (strlen(_eglBuiltInDrivers[i].name) == name_len &&
499 !strncmp(_eglBuiltInDrivers[i].name, env, name_len)) {
500 mod = _eglAddModule(env);
501 if (mod)
502 mod->BuiltIn = _eglBuiltInDrivers[i].main;
503
504 return EGL_TRUE;
505 }
506 }
507 }
508
509 /* otherwise, treat env as a path */
510 if (env) {
511 _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
512
513 return EGL_TRUE;
514 }
515
516 return EGL_FALSE;
517 }
518
519
520 /**
521 * Add built-in drivers to the module array.
522 */
523 static void
524 _eglAddBuiltInDrivers(void)
525 {
526 _EGLModule *mod;
527 EGLint i;
528
529 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
530 mod = _eglAddModule(_eglBuiltInDrivers[i].name);
531 if (mod)
532 mod->BuiltIn = _eglBuiltInDrivers[i].main;
533 }
534 }
535
536
537 /**
538 * Add drivers to the module array. Drivers will be loaded as they are matched
539 * to displays.
540 */
541 static EGLBoolean
542 _eglAddDrivers(void)
543 {
544 if (_eglModules)
545 return EGL_TRUE;
546
547 if (!_eglAddUserDriver()) {
548 /*
549 * Add other drivers only when EGL_DRIVER is not set. The order here
550 * decides the priorities.
551 */
552 _eglAddBuiltInDrivers();
553 }
554
555 return (_eglModules != NULL);
556 }
557
558
559 /**
560 * A helper function for _eglMatchDriver. It finds the first driver that can
561 * initialize the display and return.
562 */
563 static _EGLDriver *
564 _eglMatchAndInitialize(_EGLDisplay *dpy)
565 {
566 _EGLDriver *drv = NULL;
567 EGLint i = 0;
568
569 if (!_eglAddDrivers()) {
570 _eglLog(_EGL_WARNING, "failed to find any driver");
571 return NULL;
572 }
573
574 if (dpy->Driver) {
575 drv = dpy->Driver;
576 /* no re-matching? */
577 if (!drv->API.Initialize(drv, dpy))
578 drv = NULL;
579 return drv;
580 }
581
582 while (i < _eglModules->Size) {
583 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
584
585 if (!_eglLoadModule(mod)) {
586 /* remove invalid modules */
587 _eglEraseArray(_eglModules, i, _eglFreeModule);
588 continue;
589 }
590
591 if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
592 drv = mod->Driver;
593 break;
594 }
595 else {
596 i++;
597 }
598 }
599
600 return drv;
601 }
602
603
604 /**
605 * Match a display to a driver. The display is initialized unless test_only is
606 * true. The matching is done by finding the first driver that can initialize
607 * the display.
608 */
609 _EGLDriver *
610 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
611 {
612 _EGLDriver *best_drv;
613
614 assert(!dpy->Initialized);
615
616 _eglLockMutex(&_eglModuleMutex);
617
618 /* set options */
619 dpy->Options.TestOnly = test_only;
620 dpy->Options.UseFallback = EGL_FALSE;
621
622 best_drv = _eglMatchAndInitialize(dpy);
623 if (!best_drv) {
624 dpy->Options.UseFallback = EGL_TRUE;
625 best_drv = _eglMatchAndInitialize(dpy);
626 }
627
628 _eglUnlockMutex(&_eglModuleMutex);
629
630 if (best_drv) {
631 _eglLog(_EGL_DEBUG, "the best driver is %s%s",
632 best_drv->Name, (test_only) ? " (test only) " : "");
633 if (!test_only) {
634 dpy->Driver = best_drv;
635 dpy->Initialized = EGL_TRUE;
636 }
637 }
638
639 return best_drv;
640 }
641
642
643 __eglMustCastToProperFunctionPointerType
644 _eglGetDriverProc(const char *procname)
645 {
646 EGLint i;
647 _EGLProc proc = NULL;
648
649 if (!_eglModules) {
650 /* load the driver for the default display */
651 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
652 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
653 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
654 return NULL;
655 }
656
657 for (i = 0; i < _eglModules->Size; i++) {
658 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
659
660 if (!mod->Driver)
661 break;
662 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
663 if (proc)
664 break;
665 }
666
667 return proc;
668 }
669
670
671 /**
672 * Unload all drivers.
673 */
674 void
675 _eglUnloadDrivers(void)
676 {
677 /* this is called at atexit time */
678 if (_eglModules) {
679 _eglDestroyArray(_eglModules, _eglFreeModule);
680 _eglModules = NULL;
681 }
682 }
683
684
685 /**
686 * Invoke a callback function on each EGL search path.
687 *
688 * The first argument of the callback function is the name of the search path.
689 * The second argument is the length of the name.
690 */
691 void
692 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
693 void *callback_data)
694 {
695 const char *search_path = _eglGetSearchPath();
696 _eglPreloadForEach(search_path, callback, callback_data);
697 }