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