8fc9e792b061f533c0591967c2689103f7515e56
[mesa.git] / src / egl / main / egldriver.c
1 /**
2 * Functions for choosing and opening/loading device drivers.
3 */
4
5
6 #include <assert.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
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 "egllog.h"
18 #include "eglmisc.h"
19 #include "eglmode.h"
20 #include "eglscreen.h"
21 #include "eglstring.h"
22 #include "eglsurface.h"
23 #include "eglimage.h"
24 #include "eglmutex.h"
25
26 #if defined(_EGL_OS_UNIX)
27 #include <dlfcn.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <unistd.h>
31 #endif
32
33
34 typedef struct _egl_module {
35 char *Path;
36 void *Handle;
37 _EGLDriver *Driver;
38 } _EGLModule;
39
40 static _EGL_DECLARE_MUTEX(_eglModuleMutex);
41 static _EGLArray *_eglModules;
42
43
44 /**
45 * Wrappers for dlopen/dlclose()
46 */
47 #if defined(_EGL_OS_WINDOWS)
48
49
50 typedef HMODULE lib_handle;
51
52 static HMODULE
53 open_library(const char *filename)
54 {
55 return LoadLibrary(filename);
56 }
57
58 static void
59 close_library(HMODULE lib)
60 {
61 FreeLibrary(lib);
62 }
63
64
65 static const char *
66 library_suffix(void)
67 {
68 return ".dll";
69 }
70
71
72 #elif defined(_EGL_OS_UNIX)
73
74
75 typedef void * lib_handle;
76
77 static void *
78 open_library(const char *filename)
79 {
80 return dlopen(filename, RTLD_LAZY);
81 }
82
83 static void
84 close_library(void *lib)
85 {
86 dlclose(lib);
87 }
88
89
90 static const char *
91 library_suffix(void)
92 {
93 return ".so";
94 }
95
96
97 #endif
98
99
100 /**
101 * Open the named driver and find its bootstrap function: _eglMain().
102 */
103 static _EGLMain_t
104 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
105 {
106 lib_handle lib;
107 _EGLMain_t mainFunc = NULL;
108 const char *error = "unknown error";
109
110 assert(driverPath);
111
112 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
113 lib = open_library(driverPath);
114
115 #if defined(_EGL_OS_WINDOWS)
116 /* XXX untested */
117 if (lib)
118 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
119 #elif defined(_EGL_OS_UNIX)
120 if (lib) {
121 union {
122 _EGLMain_t func;
123 void *ptr;
124 } tmp = { NULL };
125 /* direct cast gives a warning when compiled with -pedantic */
126 tmp.ptr = dlsym(lib, "_eglMain");
127 mainFunc = tmp.func;
128 if (!mainFunc)
129 error = dlerror();
130 }
131 else {
132 error = dlerror();
133 }
134 #endif
135
136 if (!lib) {
137 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
138 driverPath, error);
139 if (!getenv("EGL_DRIVER"))
140 _eglLog(_EGL_WARNING,
141 "The driver can be overridden by setting EGL_DRIVER");
142 return NULL;
143 }
144
145 if (!mainFunc) {
146 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
147 driverPath, error);
148 if (lib)
149 close_library(lib);
150 return NULL;
151 }
152
153 *handle = lib;
154 return mainFunc;
155 }
156
157
158 /**
159 * Load a module and create the driver object.
160 */
161 static EGLBoolean
162 _eglLoadModule(_EGLModule *mod)
163 {
164 _EGLMain_t mainFunc;
165 lib_handle lib;
166 _EGLDriver *drv;
167
168 mainFunc = _eglOpenLibrary(mod->Path, &lib);
169 if (!mainFunc)
170 return EGL_FALSE;
171
172 drv = mainFunc(NULL);
173 if (!drv) {
174 if (lib)
175 close_library(lib);
176 return EGL_FALSE;
177 }
178
179 if (!drv->Name) {
180 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
181 drv->Name = "UNNAMED";
182 }
183
184 mod->Handle = (void *) lib;
185 mod->Driver = drv;
186
187 return EGL_TRUE;
188 }
189
190
191 /**
192 * Unload a module.
193 */
194 static void
195 _eglUnloadModule(_EGLModule *mod)
196 {
197 /* destroy the driver */
198 if (mod->Driver && mod->Driver->Unload)
199 mod->Driver->Unload(mod->Driver);
200 if (mod->Handle)
201 close_library(mod->Handle);
202
203 mod->Driver = NULL;
204 mod->Handle = NULL;
205 }
206
207
208 /**
209 * Add a module to the module array.
210 */
211 static _EGLModule *
212 _eglAddModule(const char *path)
213 {
214 _EGLModule *mod;
215 EGLint i;
216
217 if (!_eglModules) {
218 _eglModules = _eglCreateArray("Module", 8);
219 if (!_eglModules)
220 return NULL;
221 }
222
223 /* find duplicates */
224 for (i = 0; i < _eglModules->Size; i++) {
225 mod = _eglModules->Elements[i];
226 if (strcmp(mod->Path, path) == 0)
227 return mod;
228 }
229
230 /* allocate a new one */
231 mod = calloc(1, sizeof(*mod));
232 if (mod) {
233 mod->Path = _eglstrdup(path);
234 if (!mod->Path) {
235 free(mod);
236 mod = NULL;
237 }
238 }
239 if (mod) {
240 _eglAppendArray(_eglModules, (void *) mod);
241 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
242 }
243
244 return mod;
245 }
246
247
248 /**
249 * Free a module.
250 */
251 static void
252 _eglFreeModule(void *module)
253 {
254 _EGLModule *mod = (_EGLModule *) module;
255
256 _eglUnloadModule(mod);
257 free(mod->Path);
258 free(mod);
259 }
260
261
262 /**
263 * A loader function for use with _eglPreloadForEach. The loader data is the
264 * filename of the driver. This function stops on the first valid driver.
265 */
266 static EGLBoolean
267 _eglLoaderFile(const char *dir, size_t len, void *loader_data)
268 {
269 char path[1024];
270 const char *filename = (const char *) loader_data;
271 size_t flen = strlen(filename);
272
273 /* make a full path */
274 if (len + flen + 2 > sizeof(path))
275 return EGL_TRUE;
276 if (len) {
277 memcpy(path, dir, len);
278 path[len++] = '/';
279 }
280 memcpy(path + len, filename, flen);
281 len += flen;
282 path[len] = '\0';
283
284 if (library_suffix()) {
285 const char *suffix = library_suffix();
286 size_t slen = strlen(suffix);
287 const char *p;
288 EGLBoolean need_suffix;
289
290 p = filename + flen - slen;
291 need_suffix = (p < filename || strcmp(p, suffix) != 0);
292 if (need_suffix) {
293 /* overflow */
294 if (len + slen + 1 > sizeof(path))
295 return EGL_TRUE;
296 strcpy(path + len, suffix);
297 }
298 }
299
300 #if defined(_EGL_OS_UNIX)
301 /* check if the file exists */
302 if (access(path, F_OK))
303 return EGL_TRUE;
304 #endif
305
306 _eglAddModule(path);
307
308 return EGL_TRUE;
309 }
310
311
312 /**
313 * A loader function for use with _eglPreloadForEach. The loader data is the
314 * pattern (prefix) of the files to look for.
315 */
316 static EGLBoolean
317 _eglLoaderPattern(const char *dir, size_t len, void *loader_data)
318 {
319 #if defined(_EGL_OS_UNIX)
320 const char *prefix, *suffix;
321 size_t prefix_len, suffix_len;
322 DIR *dirp;
323 struct dirent *dirent;
324 char path[1024];
325
326 if (len + 2 > sizeof(path))
327 return EGL_TRUE;
328 if (len) {
329 memcpy(path, dir, len);
330 path[len++] = '/';
331 }
332 path[len] = '\0';
333
334 dirp = opendir(path);
335 if (!dirp)
336 return EGL_TRUE;
337
338 prefix = (const char *) loader_data;
339 prefix_len = strlen(prefix);
340 suffix = library_suffix();
341 suffix_len = (suffix) ? strlen(suffix) : 0;
342
343 while ((dirent = readdir(dirp))) {
344 size_t dirent_len = strlen(dirent->d_name);
345 const char *p;
346
347 /* match the prefix */
348 if (strncmp(dirent->d_name, prefix, prefix_len) != 0)
349 continue;
350 /* match the suffix */
351 if (suffix) {
352 p = dirent->d_name + dirent_len - suffix_len;
353 if (p < dirent->d_name || strcmp(p, suffix) != 0)
354 continue;
355 }
356
357 /* make a full path and add it to the module array */
358 if (len + dirent_len + 1 <= sizeof(path)) {
359 strcpy(path + len, dirent->d_name);
360 _eglAddModule(path);
361 }
362 }
363
364 closedir(dirp);
365
366 return EGL_TRUE;
367 #else /* _EGL_OS_UNIX */
368 /* stop immediately */
369 return EGL_FALSE;
370 #endif
371 }
372
373
374 /**
375 * Run the callback function on each driver directory.
376 *
377 * The process may end prematurely if the callback function returns false.
378 */
379 static void
380 _eglPreloadForEach(const char *search_path,
381 EGLBoolean (*loader)(const char *, size_t, void *),
382 void *loader_data)
383 {
384 const char *cur, *next;
385 size_t len;
386
387 cur = search_path;
388 while (cur) {
389 next = strchr(cur, ':');
390 len = (next) ? next - cur : strlen(cur);
391
392 if (!loader(cur, len, loader_data))
393 break;
394
395 cur = (next) ? next + 1 : NULL;
396 }
397 }
398
399
400 /**
401 * Return a list of colon-separated driver directories.
402 */
403 static const char *
404 _eglGetSearchPath(void)
405 {
406 static const char *search_path;
407
408 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
409 if (!search_path) {
410 static char buffer[1024];
411 const char *p;
412 int ret;
413
414 p = getenv("EGL_DRIVERS_PATH");
415 #if defined(_EGL_OS_UNIX)
416 if (p && (geteuid() != getuid() || getegid() != getgid())) {
417 _eglLog(_EGL_DEBUG,
418 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
419 p = NULL;
420 }
421 #endif /* _EGL_OS_UNIX */
422
423 if (p) {
424 ret = _eglsnprintf(buffer, sizeof(buffer),
425 "%s:%s", p, _EGL_DRIVER_SEARCH_DIR);
426 if (ret > 0 && ret < sizeof(buffer))
427 search_path = buffer;
428 }
429 }
430 if (!search_path)
431 search_path = _EGL_DRIVER_SEARCH_DIR;
432 #else
433 search_path = "";
434 #endif
435
436 return search_path;
437 }
438
439
440 /**
441 * Add the user driver to the module array.
442 *
443 * The user driver is specified by EGL_DRIVER.
444 */
445 static void
446 _eglAddUserDriver(void)
447 {
448 const char *search_path = _eglGetSearchPath();
449 char *env;
450
451 env = getenv("EGL_DRIVER");
452 #if defined(_EGL_OS_UNIX)
453 if (env && strchr(env, '/')) {
454 search_path = "";
455 if ((geteuid() != getuid() || getegid() != getgid())) {
456 _eglLog(_EGL_DEBUG,
457 "ignore EGL_DRIVER for setuid/setgid binaries");
458 env = NULL;
459 }
460 }
461 #endif /* _EGL_OS_UNIX */
462 if (env)
463 _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
464 }
465
466
467 /**
468 * Add default drivers to the module array.
469 */
470 static void
471 _eglAddDefaultDrivers(void)
472 {
473 const char *search_path = _eglGetSearchPath();
474 EGLint i;
475 #if defined(_EGL_OS_WINDOWS)
476 const char *DefaultDriverNames[] = {
477 "egl_gallium"
478 };
479 #elif defined(_EGL_OS_UNIX)
480 const char *DefaultDriverNames[] = {
481 "egl_gallium",
482 "egl_dri2",
483 "egl_glx"
484 };
485 #endif
486
487 for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
488 void *name = (void *) DefaultDriverNames[i];
489 _eglPreloadForEach(search_path, _eglLoaderFile, name);
490 }
491 }
492
493
494 /**
495 * Add drivers to the module array. Drivers will be loaded as they are matched
496 * to displays.
497 */
498 static EGLBoolean
499 _eglAddDrivers(void)
500 {
501 if (_eglModules)
502 return EGL_TRUE;
503
504 /* the order here decides the priorities of the drivers */
505 _eglAddUserDriver();
506 _eglAddDefaultDrivers();
507 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderPattern, (void *) "egl_");
508
509 return (_eglModules != NULL);
510 }
511
512
513 /**
514 * Match a display to a driver. The display is initialized unless use_probe is
515 * true.
516 *
517 * The matching is done by finding the first driver that can initialize the
518 * display, or when use_probe is true, the driver with highest score.
519 */
520 _EGLDriver *
521 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean use_probe)
522 {
523 _EGLModule *mod;
524 _EGLDriver *best_drv = NULL;
525 EGLint best_score = 0;
526 EGLint major, minor, i;
527
528 _eglLockMutex(&_eglModuleMutex);
529
530 if (!_eglAddDrivers()) {
531 _eglUnlockMutex(&_eglModuleMutex);
532 return EGL_FALSE;
533 }
534
535 /* match the loaded modules */
536 for (i = 0; i < _eglModules->Size; i++) {
537 mod = (_EGLModule *) _eglModules->Elements[i];
538 if (!mod->Driver)
539 break;
540
541 if (use_probe) {
542 EGLint score = (mod->Driver->Probe) ?
543 mod->Driver->Probe(mod->Driver, dpy) : 1;
544 if (score > best_score) {
545 best_drv = mod->Driver;
546 best_score = score;
547 }
548 }
549 else {
550 if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor)) {
551 best_drv = mod->Driver;
552 best_score = 100;
553 }
554 }
555 /* perfect match */
556 if (best_score >= 100)
557 break;
558 }
559
560 /* load more modules */
561 if (!best_drv) {
562 EGLint first_unloaded = i;
563
564 while (i < _eglModules->Size) {
565 mod = (_EGLModule *) _eglModules->Elements[i];
566 assert(!mod->Driver);
567
568 if (!_eglLoadModule(mod)) {
569 /* remove invalid modules */
570 _eglEraseArray(_eglModules, i, _eglFreeModule);
571 continue;
572 }
573
574 if (use_probe) {
575 best_score = (mod->Driver->Probe) ?
576 mod->Driver->Probe(mod->Driver, dpy) : 1;
577 }
578 else {
579 if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor))
580 best_score = 100;
581 }
582
583 if (best_score > 0) {
584 best_drv = mod->Driver;
585 /* loaded modules come before unloaded ones */
586 if (first_unloaded != i) {
587 void *tmp = _eglModules->Elements[i];
588 _eglModules->Elements[i] =
589 _eglModules->Elements[first_unloaded];
590 _eglModules->Elements[first_unloaded] = tmp;
591 }
592 break;
593 }
594 else {
595 _eglUnloadModule(mod);
596 i++;
597 }
598 }
599 }
600
601 _eglUnlockMutex(&_eglModuleMutex);
602
603 if (best_drv) {
604 _eglLog(_EGL_DEBUG, "the best driver is %s (score %d)",
605 best_drv->Name, best_score);
606 if (!use_probe) {
607 dpy->Driver = best_drv;
608 dpy->Initialized = EGL_TRUE;
609 dpy->APImajor = major;
610 dpy->APIminor = minor;
611 }
612 }
613
614 return best_drv;
615 }
616
617
618 __eglMustCastToProperFunctionPointerType
619 _eglGetDriverProc(const char *procname)
620 {
621 EGLint i;
622 _EGLProc proc = NULL;
623
624 if (!_eglModules) {
625 /* load the driver for the default display */
626 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
627 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
628 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
629 return NULL;
630 }
631
632 for (i = 0; i < _eglModules->Size; i++) {
633 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
634
635 if (!mod->Driver)
636 break;
637 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
638 if (proc)
639 break;
640 }
641
642 return proc;
643 }
644
645
646 /**
647 * Unload all drivers.
648 */
649 void
650 _eglUnloadDrivers(void)
651 {
652 /* this is called at atexit time */
653 if (_eglModules) {
654 #if defined(_EGL_OS_UNIX)
655 _eglDestroyArray(_eglModules, _eglFreeModule);
656 #elif defined(_EGL_OS_WINDOWS)
657 /* XXX Windows unloads DLLs before atexit */
658 _eglDestroyArray(_eglModules, NULL);
659 #endif
660 _eglModules = NULL;
661 }
662 }
663
664
665 /**
666 * Plug all the available fallback routines into the given driver's
667 * dispatch table.
668 */
669 void
670 _eglInitDriverFallbacks(_EGLDriver *drv)
671 {
672 /* If a pointer is set to NULL, then the device driver _really_ has
673 * to implement it.
674 */
675 drv->API.Initialize = NULL;
676 drv->API.Terminate = NULL;
677
678 drv->API.GetConfigs = _eglGetConfigs;
679 drv->API.ChooseConfig = _eglChooseConfig;
680 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
681
682 drv->API.CreateContext = _eglCreateContext;
683 drv->API.DestroyContext = _eglDestroyContext;
684 drv->API.MakeCurrent = _eglMakeCurrent;
685 drv->API.QueryContext = _eglQueryContext;
686
687 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
688 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
689 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
690 drv->API.DestroySurface = _eglDestroySurface;
691 drv->API.QuerySurface = _eglQuerySurface;
692 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
693 drv->API.BindTexImage = _eglBindTexImage;
694 drv->API.ReleaseTexImage = _eglReleaseTexImage;
695 drv->API.SwapInterval = _eglSwapInterval;
696 drv->API.SwapBuffers = _eglSwapBuffers;
697 drv->API.CopyBuffers = _eglCopyBuffers;
698
699 drv->API.QueryString = _eglQueryString;
700 drv->API.WaitClient = _eglWaitClient;
701 drv->API.WaitNative = _eglWaitNative;
702
703 #ifdef EGL_MESA_screen_surface
704 drv->API.ChooseModeMESA = _eglChooseModeMESA;
705 drv->API.GetModesMESA = _eglGetModesMESA;
706 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
707 drv->API.GetScreensMESA = _eglGetScreensMESA;
708 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
709 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
710 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
711 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
712 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
713 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
714 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
715 #endif /* EGL_MESA_screen_surface */
716
717 #ifdef EGL_VERSION_1_2
718 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
719 #endif /* EGL_VERSION_1_2 */
720
721 #ifdef EGL_KHR_image_base
722 drv->API.CreateImageKHR = _eglCreateImageKHR;
723 drv->API.DestroyImageKHR = _eglDestroyImageKHR;
724 #endif /* EGL_KHR_image_base */
725 }
726
727
728 /**
729 * Invoke a callback function on each EGL search path.
730 *
731 * The first argument of the callback function is the name of the search path.
732 * The second argument is the length of the name.
733 */
734 void
735 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
736 void *callback_data)
737 {
738 const char *search_path = _eglGetSearchPath();
739 _eglPreloadForEach(search_path, callback, callback_data);
740 }