78d81309265bea8285615fd8d67ff96d73814e68
[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 egl_gallium to the module array.
522 */
523 static void
524 _eglAddGalliumDriver(void)
525 {
526 #ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
527 void *external = (void *) "egl_gallium";
528 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external);
529 #endif
530 }
531
532
533 /**
534 * Add built-in drivers to the module array.
535 */
536 static void
537 _eglAddBuiltInDrivers(void)
538 {
539 _EGLModule *mod;
540 EGLint i;
541
542 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
543 mod = _eglAddModule(_eglBuiltInDrivers[i].name);
544 if (mod)
545 mod->BuiltIn = _eglBuiltInDrivers[i].main;
546 }
547 }
548
549
550 /**
551 * Add drivers to the module array. Drivers will be loaded as they are matched
552 * to displays.
553 */
554 static EGLBoolean
555 _eglAddDrivers(void)
556 {
557 if (_eglModules)
558 return EGL_TRUE;
559
560 if (!_eglAddUserDriver()) {
561 /*
562 * Add other drivers only when EGL_DRIVER is not set. The order here
563 * decides the priorities.
564 */
565 _eglAddGalliumDriver();
566 _eglAddBuiltInDrivers();
567 }
568
569 return (_eglModules != NULL);
570 }
571
572
573 /**
574 * A helper function for _eglMatchDriver. It finds the first driver that can
575 * initialize the display and return.
576 */
577 static _EGLDriver *
578 _eglMatchAndInitialize(_EGLDisplay *dpy)
579 {
580 _EGLDriver *drv = NULL;
581 EGLint i = 0;
582
583 if (!_eglAddDrivers()) {
584 _eglLog(_EGL_WARNING, "failed to find any driver");
585 return NULL;
586 }
587
588 if (dpy->Driver) {
589 drv = dpy->Driver;
590 /* no re-matching? */
591 if (!drv->API.Initialize(drv, dpy))
592 drv = NULL;
593 return drv;
594 }
595
596 while (i < _eglModules->Size) {
597 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
598
599 if (!_eglLoadModule(mod)) {
600 /* remove invalid modules */
601 _eglEraseArray(_eglModules, i, _eglFreeModule);
602 continue;
603 }
604
605 if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
606 drv = mod->Driver;
607 break;
608 }
609 else {
610 i++;
611 }
612 }
613
614 return drv;
615 }
616
617
618 /**
619 * Match a display to a driver. The display is initialized unless test_only is
620 * true. The matching is done by finding the first driver that can initialize
621 * the display.
622 */
623 _EGLDriver *
624 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
625 {
626 _EGLDriver *best_drv;
627
628 assert(!dpy->Initialized);
629
630 _eglLockMutex(&_eglModuleMutex);
631
632 /* set options */
633 dpy->Options.TestOnly = test_only;
634 dpy->Options.UseFallback = EGL_FALSE;
635
636 best_drv = _eglMatchAndInitialize(dpy);
637 if (!best_drv) {
638 dpy->Options.UseFallback = EGL_TRUE;
639 best_drv = _eglMatchAndInitialize(dpy);
640 }
641
642 _eglUnlockMutex(&_eglModuleMutex);
643
644 if (best_drv) {
645 _eglLog(_EGL_DEBUG, "the best driver is %s%s",
646 best_drv->Name, (test_only) ? " (test only) " : "");
647 if (!test_only) {
648 dpy->Driver = best_drv;
649 dpy->Initialized = EGL_TRUE;
650 }
651 }
652
653 return best_drv;
654 }
655
656
657 __eglMustCastToProperFunctionPointerType
658 _eglGetDriverProc(const char *procname)
659 {
660 EGLint i;
661 _EGLProc proc = NULL;
662
663 if (!_eglModules) {
664 /* load the driver for the default display */
665 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
666 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
667 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
668 return NULL;
669 }
670
671 for (i = 0; i < _eglModules->Size; i++) {
672 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
673
674 if (!mod->Driver)
675 break;
676 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
677 if (proc)
678 break;
679 }
680
681 return proc;
682 }
683
684
685 /**
686 * Unload all drivers.
687 */
688 void
689 _eglUnloadDrivers(void)
690 {
691 /* this is called at atexit time */
692 if (_eglModules) {
693 _eglDestroyArray(_eglModules, _eglFreeModule);
694 _eglModules = NULL;
695 }
696 }
697
698
699 /**
700 * Invoke a callback function on each EGL search path.
701 *
702 * The first argument of the callback function is the name of the search path.
703 * The second argument is the length of the name.
704 */
705 void
706 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
707 void *callback_data)
708 {
709 const char *search_path = _eglGetSearchPath();
710 _eglPreloadForEach(search_path, callback, callback_data);
711 }