631a8710ac5af1b01f6de0954c99b6a23d2c5d4f
[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
26 #if defined(_EGL_PLATFORM_POSIX)
27 #include <dlfcn.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <unistd.h>
31 #endif
32
33
34 /**
35 * Wrappers for dlopen/dlclose()
36 */
37 #if defined(_EGL_PLATFORM_WINDOWS)
38
39
40 /* XXX Need to decide how to do dynamic name lookup on Windows */
41 static const char *DefaultDriverNames[] = {
42 "egl_gdi_swrast"
43 };
44
45 typedef HMODULE lib_handle;
46
47 static HMODULE
48 open_library(const char *filename)
49 {
50 return LoadLibrary(filename);
51 }
52
53 static void
54 close_library(HMODULE lib)
55 {
56 FreeLibrary(lib);
57 }
58
59
60 static const char *
61 library_suffix(void)
62 {
63 return ".dll";
64 }
65
66
67 #elif defined(_EGL_PLATFORM_POSIX)
68
69
70 static const char *DefaultDriverNames[] = {
71 "egl_dri2",
72 "egl_glx"
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 #define NUM_PROBE_CACHE_SLOTS 8
101 static struct {
102 EGLint keys[NUM_PROBE_CACHE_SLOTS];
103 const void *values[NUM_PROBE_CACHE_SLOTS];
104 } _eglProbeCache;
105
106
107 /**
108 * Open the named driver and find its bootstrap function: _eglMain().
109 */
110 static _EGLMain_t
111 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
112 {
113 lib_handle lib;
114 _EGLMain_t mainFunc = NULL;
115 const char *error = "unknown error";
116
117 assert(driverPath);
118
119 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
120 lib = open_library(driverPath);
121
122 #if defined(_EGL_PLATFORM_WINDOWS)
123 /* XXX untested */
124 if (lib)
125 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
126 #elif defined(_EGL_PLATFORM_POSIX)
127 if (lib) {
128 union {
129 _EGLMain_t func;
130 void *ptr;
131 } tmp = { NULL };
132 /* direct cast gives a warning when compiled with -pedantic */
133 tmp.ptr = dlsym(lib, "_eglMain");
134 mainFunc = tmp.func;
135 if (!mainFunc)
136 error = dlerror();
137 }
138 else {
139 error = dlerror();
140 }
141 #endif
142
143 if (!lib) {
144 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
145 driverPath, error);
146 if (!getenv("EGL_DRIVER"))
147 _eglLog(_EGL_WARNING,
148 "The driver can be overridden by setting EGL_DRIVER");
149 return NULL;
150 }
151
152 if (!mainFunc) {
153 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
154 driverPath, error);
155 if (lib)
156 close_library(lib);
157 return NULL;
158 }
159
160 *handle = lib;
161 return mainFunc;
162 }
163
164
165 /**
166 * Load the named driver.
167 */
168 static _EGLDriver *
169 _eglLoadDriver(const char *path, const char *args)
170 {
171 _EGLMain_t mainFunc;
172 lib_handle lib;
173 _EGLDriver *drv = NULL;
174
175 mainFunc = _eglOpenLibrary(path, &lib);
176 if (!mainFunc)
177 return NULL;
178
179 drv = mainFunc(args);
180 if (!drv) {
181 if (lib)
182 close_library(lib);
183 return NULL;
184 }
185
186 if (!drv->Name) {
187 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
188 drv->Name = "UNNAMED";
189 }
190
191 drv->Path = _eglstrdup(path);
192 drv->Args = (args) ? _eglstrdup(args) : NULL;
193 if (!drv->Path || (args && !drv->Args)) {
194 if (drv->Path)
195 free((char *) drv->Path);
196 if (drv->Args)
197 free((char *) drv->Args);
198 drv->Unload(drv);
199 if (lib)
200 close_library(lib);
201 return NULL;
202 }
203
204 drv->LibHandle = lib;
205
206 return drv;
207 }
208
209
210 /**
211 * Match a display to a preloaded driver.
212 *
213 * The matching is done by finding the driver with the highest score.
214 */
215 _EGLDriver *
216 _eglMatchDriver(_EGLDisplay *dpy)
217 {
218 _EGLDriver *best_drv = NULL;
219 EGLint best_score = -1, i;
220
221 /*
222 * this function is called after preloading and the drivers never change
223 * after preloading.
224 */
225 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
226 _EGLDriver *drv = _eglGlobal.Drivers[i];
227 EGLint score;
228
229 score = (drv->Probe) ? drv->Probe(drv, dpy) : 0;
230 if (score > best_score) {
231 if (best_drv) {
232 _eglLog(_EGL_DEBUG, "driver %s has higher score than %s",
233 drv->Name, best_drv->Name);
234 }
235
236 best_drv = drv;
237 best_score = score;
238 /* perfect match */
239 if (score >= 100)
240 break;
241 }
242 }
243
244 return best_drv;
245 }
246
247
248 /**
249 * A loader function for use with _eglPreloadForEach. The loader data is the
250 * filename of the driver. This function stops on the first valid driver.
251 */
252 static EGLBoolean
253 _eglLoaderFile(const char *dir, size_t len, void *loader_data)
254 {
255 _EGLDriver *drv;
256 char path[1024];
257 const char *filename = (const char *) loader_data;
258 size_t flen = strlen(filename);
259
260 /* make a full path */
261 if (len + flen + 2 > sizeof(path))
262 return EGL_TRUE;
263 if (len) {
264 memcpy(path, dir, len);
265 path[len++] = '/';
266 }
267 memcpy(path + len, filename, flen);
268 len += flen;
269 path[len] = '\0';
270
271 if (library_suffix() == NULL || strstr(path, library_suffix()))
272 drv = _eglLoadDriver(path, NULL);
273 else {
274 const char *suffix = library_suffix();
275 size_t slen = strlen(suffix);
276 const char *p;
277 EGLBoolean need_suffix;
278
279 p = filename + flen - slen;
280 need_suffix = (p < filename || strcmp(p, suffix) != 0);
281 if (need_suffix && len + slen + 1 <= sizeof(path)) {
282 strcpy(path + len, suffix);
283 drv = _eglLoadDriver(path, NULL);
284 } else {
285 drv = NULL;
286 }
287 }
288 if (!drv)
289 return EGL_TRUE;
290
291 /* remember the driver and stop */
292 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
293 return EGL_FALSE;
294 }
295
296
297 /**
298 * A loader function for use with _eglPreloadForEach. The loader data is the
299 * pattern (prefix) of the files to look for.
300 */
301 static EGLBoolean
302 _eglLoaderPattern(const char *dir, size_t len, void *loader_data)
303 {
304 #if defined(_EGL_PLATFORM_POSIX)
305 const char *prefix, *suffix;
306 size_t prefix_len, suffix_len;
307 DIR *dirp;
308 struct dirent *dirent;
309 char path[1024];
310
311 if (len + 2 > sizeof(path))
312 return EGL_TRUE;
313 if (len) {
314 memcpy(path, dir, len);
315 path[len++] = '/';
316 }
317 path[len] = '\0';
318
319 dirp = opendir(path);
320 if (!dirp)
321 return EGL_TRUE;
322
323 prefix = (const char *) loader_data;
324 prefix_len = strlen(prefix);
325 suffix = library_suffix();
326 suffix_len = (suffix) ? strlen(suffix) : 0;
327
328 while ((dirent = readdir(dirp))) {
329 _EGLDriver *drv;
330 size_t dirent_len = strlen(dirent->d_name);
331 const char *p;
332
333 /* match the prefix */
334 if (strncmp(dirent->d_name, prefix, prefix_len) != 0)
335 continue;
336 /* match the suffix */
337 if (suffix) {
338 p = dirent->d_name + dirent_len - suffix_len;
339 if (p < dirent->d_name || strcmp(p, suffix) != 0)
340 continue;
341 }
342
343 /* make a full path and load the driver */
344 if (len + dirent_len + 1 <= sizeof(path)) {
345 strcpy(path + len, dirent->d_name);
346 drv = _eglLoadDriver(path, NULL);
347 if (drv)
348 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
349 }
350 }
351
352 closedir(dirp);
353
354 return EGL_TRUE;
355 #else /* _EGL_PLATFORM_POSIX */
356 /* stop immediately */
357 return EGL_FALSE;
358 #endif
359 }
360
361
362 /**
363 * Run the preload function on each driver directory and return the number of
364 * drivers loaded.
365 *
366 * The process may end prematurely if the callback function returns false.
367 */
368 static EGLint
369 _eglPreloadForEach(const char *search_path,
370 EGLBoolean (*loader)(const char *, size_t, void *),
371 void *loader_data)
372 {
373 const char *cur, *next;
374 size_t len;
375 EGLint num_drivers = _eglGlobal.NumDrivers;
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 return (_eglGlobal.NumDrivers - num_drivers);
389 }
390
391
392 /**
393 * Return a list of colon-separated driver directories.
394 */
395 static const char *
396 _eglGetSearchPath(void)
397 {
398 static const char *search_path;
399
400 #if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS)
401 if (!search_path) {
402 static char buffer[1024];
403 const char *p;
404 int ret;
405
406 p = getenv("EGL_DRIVERS_PATH");
407 #if defined(_EGL_PLATFORM_POSIX)
408 if (p && (geteuid() != getuid() || getegid() != getgid())) {
409 _eglLog(_EGL_DEBUG,
410 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
411 p = NULL;
412 }
413 #endif /* _EGL_PLATFORM_POSIX */
414
415 if (p) {
416 ret = _eglsnprintf(buffer, sizeof(buffer),
417 "%s:%s", p, _EGL_DRIVER_SEARCH_DIR);
418 if (ret > 0 && ret < sizeof(buffer))
419 search_path = buffer;
420 }
421 }
422 if (!search_path)
423 search_path = _EGL_DRIVER_SEARCH_DIR;
424 #else
425 search_path = "";
426 #endif
427
428 return search_path;
429 }
430
431
432 /**
433 * Preload a user driver.
434 *
435 * A user driver can be specified by EGL_DRIVER.
436 */
437 static EGLBoolean
438 _eglPreloadUserDriver(void)
439 {
440 const char *search_path = _eglGetSearchPath();
441 char *env;
442
443 env = getenv("EGL_DRIVER");
444 #if defined(_EGL_PLATFORM_POSIX)
445 if (env && strchr(env, '/')) {
446 search_path = "";
447 if ((geteuid() != getuid() || getegid() != getgid())) {
448 _eglLog(_EGL_DEBUG,
449 "ignore EGL_DRIVER for setuid/setgid binaries");
450 env = NULL;
451 }
452 }
453 #endif /* _EGL_PLATFORM_POSIX */
454 if (!env)
455 return EGL_FALSE;
456
457 if (!_eglPreloadForEach(search_path, _eglLoaderFile, (void *) env)) {
458 _eglLog(_EGL_WARNING, "EGL_DRIVER is set to an invalid driver");
459 return EGL_FALSE;
460 }
461
462 return EGL_TRUE;
463 }
464
465
466 /**
467 * Preload display drivers.
468 *
469 * Display drivers are a set of drivers that support a certain display system.
470 * The display system may be specified by EGL_DISPLAY.
471 *
472 * FIXME This makes libEGL a memory hog if an user driver is not specified and
473 * there are many display drivers.
474 */
475 static EGLBoolean
476 _eglPreloadDisplayDrivers(void)
477 {
478 const char *dpy;
479 char prefix[32];
480 int ret;
481
482 dpy = getenv("EGL_DISPLAY");
483 if (!dpy || !dpy[0])
484 dpy = _EGL_DEFAULT_DISPLAY;
485 if (!dpy || !dpy[0])
486 return EGL_FALSE;
487
488 ret = _eglsnprintf(prefix, sizeof(prefix), "egl_%s_", dpy);
489 if (ret < 0 || ret >= sizeof(prefix))
490 return EGL_FALSE;
491
492 return (_eglPreloadForEach(_eglGetSearchPath(),
493 _eglLoaderPattern, (void *) prefix) > 0);
494 }
495
496
497 /**
498 * Preload drivers.
499 *
500 * This function loads the driver modules and creates the corresponding
501 * _EGLDriver objects.
502 */
503 EGLBoolean
504 _eglPreloadDrivers(void)
505 {
506 EGLBoolean loaded;
507
508 /* protect the preloading process */
509 _eglLockMutex(_eglGlobal.Mutex);
510
511 /* already preloaded */
512 if (_eglGlobal.NumDrivers) {
513 _eglUnlockMutex(_eglGlobal.Mutex);
514 return EGL_TRUE;
515 }
516
517 loaded = (_eglPreloadUserDriver() ||
518 _eglPreloadDisplayDrivers());
519
520 _eglUnlockMutex(_eglGlobal.Mutex);
521
522 return loaded;
523 }
524
525 /**
526 * Unload preloaded drivers.
527 */
528 void
529 _eglUnloadDrivers(void)
530 {
531 EGLint i;
532
533 /* this is called at atexit time */
534 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
535 _EGLDriver *drv = _eglGlobal.Drivers[i];
536 lib_handle handle = drv->LibHandle;
537
538 if (drv->Path)
539 free((char *) drv->Path);
540 if (drv->Args)
541 free((char *) drv->Args);
542
543 /* destroy driver */
544 if (drv->Unload)
545 drv->Unload(drv);
546
547 if (handle)
548 close_library(handle);
549 _eglGlobal.Drivers[i] = NULL;
550 }
551
552 _eglGlobal.NumDrivers = 0;
553 }
554
555 _EGLDriver *
556 _eglLoadDefaultDriver(EGLDisplay dpy, EGLint *major, EGLint *minor)
557 {
558 _EGLDriver *drv = NULL;
559 int i;
560
561 _eglLockMutex(_eglGlobal.Mutex);
562
563 for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
564 _eglPreloadForEach(_eglGetSearchPath(),
565 _eglLoaderFile, (void *) DefaultDriverNames[i]);
566 if (_eglGlobal.NumDrivers == 0)
567 continue;
568 drv = _eglGlobal.Drivers[0];
569 if (drv->API.Initialize(drv, dpy, major, minor))
570 break;
571 _eglUnloadDrivers();
572 }
573
574 _eglUnlockMutex(_eglGlobal.Mutex);
575
576 return _eglGlobal.NumDrivers > 0 ? drv : NULL;
577 }
578
579
580 /**
581 * Plug all the available fallback routines into the given driver's
582 * dispatch table.
583 */
584 void
585 _eglInitDriverFallbacks(_EGLDriver *drv)
586 {
587 /* If a pointer is set to NULL, then the device driver _really_ has
588 * to implement it.
589 */
590 drv->API.Initialize = NULL;
591 drv->API.Terminate = NULL;
592
593 drv->API.GetConfigs = _eglGetConfigs;
594 drv->API.ChooseConfig = _eglChooseConfig;
595 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
596
597 drv->API.CreateContext = _eglCreateContext;
598 drv->API.DestroyContext = _eglDestroyContext;
599 drv->API.MakeCurrent = _eglMakeCurrent;
600 drv->API.QueryContext = _eglQueryContext;
601
602 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
603 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
604 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
605 drv->API.DestroySurface = _eglDestroySurface;
606 drv->API.QuerySurface = _eglQuerySurface;
607 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
608 drv->API.BindTexImage = _eglBindTexImage;
609 drv->API.ReleaseTexImage = _eglReleaseTexImage;
610 drv->API.SwapInterval = _eglSwapInterval;
611 drv->API.SwapBuffers = _eglSwapBuffers;
612 drv->API.CopyBuffers = _eglCopyBuffers;
613
614 drv->API.QueryString = _eglQueryString;
615 drv->API.WaitClient = _eglWaitClient;
616 drv->API.WaitNative = _eglWaitNative;
617
618 #ifdef EGL_MESA_screen_surface
619 drv->API.ChooseModeMESA = _eglChooseModeMESA;
620 drv->API.GetModesMESA = _eglGetModesMESA;
621 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
622 drv->API.GetScreensMESA = _eglGetScreensMESA;
623 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
624 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
625 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
626 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
627 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
628 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
629 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
630 #endif /* EGL_MESA_screen_surface */
631
632 #ifdef EGL_VERSION_1_2
633 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
634 #endif /* EGL_VERSION_1_2 */
635
636 #ifdef EGL_KHR_image_base
637 drv->API.CreateImageKHR = _eglCreateImageKHR;
638 drv->API.DestroyImageKHR = _eglDestroyImageKHR;
639 #endif /* EGL_KHR_image_base */
640 }
641
642
643 /**
644 * Invoke a callback function on each EGL search path.
645 *
646 * The first argument of the callback function is the name of the search path.
647 * The second argument is the length of the name.
648 */
649 void
650 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
651 void *callback_data)
652 {
653 const char *search_path = _eglGetSearchPath();
654 _eglPreloadForEach(search_path, callback, callback_data);
655 }
656
657
658 /**
659 * Set the probe cache at the given key.
660 *
661 * A key, instead of a _EGLDriver, is used to allow the probe cache to be share
662 * by multiple drivers.
663 */
664 void
665 _eglSetProbeCache(EGLint key, const void *val)
666 {
667 EGLint idx;
668
669 for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) {
670 if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key)
671 break;
672 }
673 assert(key > 0);
674 assert(idx < NUM_PROBE_CACHE_SLOTS);
675
676 _eglProbeCache.keys[idx] = key;
677 _eglProbeCache.values[idx] = val;
678 }
679
680
681 /**
682 * Return the probe cache at the given key.
683 */
684 const void *
685 _eglGetProbeCache(EGLint key)
686 {
687 EGLint idx;
688
689 for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) {
690 if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key)
691 break;
692 }
693
694 return (idx < NUM_PROBE_CACHE_SLOTS && _eglProbeCache.keys[idx] == key) ?
695 _eglProbeCache.values[idx] : NULL;
696 }