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