db7b4a7471e32b641249a8350964514b28d59019
[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_OS_UNIX)
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_OS_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_OS_UNIX)
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_OS_WINDOWS)
123 /* XXX untested */
124 if (lib)
125 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
126 #elif defined(_EGL_OS_UNIX)
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_OS_UNIX)
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_OS_UNIX */
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_OS_UNIX) || defined(_EGL_OS_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_OS_UNIX)
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_OS_UNIX */
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_OS_UNIX)
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_OS_UNIX */
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 platform drivers.
468 *
469 * Platform drivers are a set of drivers that support a certain window system.
470 * The window system may be specified by EGL_PLATFORM.
471 *
472 * FIXME This makes libEGL a memory hog if an user driver is not specified and
473 * there are many platform drivers.
474 */
475 static EGLBoolean
476 _eglPreloadPlatformDrivers(void)
477 {
478 const char *dpy;
479 char prefix[32];
480 int ret;
481
482 dpy = getenv("EGL_PLATFORM");
483 /* try deprecated env variable */
484 if (!dpy || !dpy[0])
485 dpy = getenv("EGL_DISPLAY");
486 if (!dpy || !dpy[0])
487 dpy = _EGL_DEFAULT_PLATFORM;
488 if (!dpy || !dpy[0])
489 return EGL_FALSE;
490
491 ret = _eglsnprintf(prefix, sizeof(prefix), "egl_%s_", dpy);
492 if (ret < 0 || ret >= sizeof(prefix))
493 return EGL_FALSE;
494
495 return (_eglPreloadForEach(_eglGetSearchPath(),
496 _eglLoaderPattern, (void *) prefix) > 0);
497 }
498
499
500 /**
501 * Preload drivers.
502 *
503 * This function loads the driver modules and creates the corresponding
504 * _EGLDriver objects.
505 */
506 EGLBoolean
507 _eglPreloadDrivers(void)
508 {
509 EGLBoolean loaded;
510
511 /* protect the preloading process */
512 _eglLockMutex(_eglGlobal.Mutex);
513
514 /* already preloaded */
515 if (_eglGlobal.NumDrivers) {
516 _eglUnlockMutex(_eglGlobal.Mutex);
517 return EGL_TRUE;
518 }
519
520 loaded = (_eglPreloadUserDriver() ||
521 _eglPreloadPlatformDrivers());
522
523 _eglUnlockMutex(_eglGlobal.Mutex);
524
525 return loaded;
526 }
527
528 /**
529 * Unload preloaded drivers.
530 */
531 void
532 _eglUnloadDrivers(void)
533 {
534 EGLint i;
535
536 /* this is called at atexit time */
537 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
538 _EGLDriver *drv = _eglGlobal.Drivers[i];
539 lib_handle handle = drv->LibHandle;
540
541 if (drv->Path)
542 free((char *) drv->Path);
543 if (drv->Args)
544 free((char *) drv->Args);
545
546 /* destroy driver */
547 if (drv->Unload)
548 drv->Unload(drv);
549
550 if (handle)
551 close_library(handle);
552 _eglGlobal.Drivers[i] = NULL;
553 }
554
555 _eglGlobal.NumDrivers = 0;
556 }
557
558 _EGLDriver *
559 _eglLoadDefaultDriver(EGLDisplay dpy, EGLint *major, EGLint *minor)
560 {
561 _EGLDriver *drv = NULL;
562 int i;
563
564 _eglLockMutex(_eglGlobal.Mutex);
565
566 for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
567 _eglPreloadForEach(_eglGetSearchPath(),
568 _eglLoaderFile, (void *) DefaultDriverNames[i]);
569 if (_eglGlobal.NumDrivers == 0)
570 continue;
571 drv = _eglGlobal.Drivers[0];
572 if (drv->API.Initialize(drv, dpy, major, minor))
573 break;
574 _eglUnloadDrivers();
575 }
576
577 _eglUnlockMutex(_eglGlobal.Mutex);
578
579 return _eglGlobal.NumDrivers > 0 ? drv : NULL;
580 }
581
582
583 /**
584 * Return the native platform. It is the platform of the EGL native types.
585 */
586 _EGLPlatformType
587 _eglGetNativePlatform(void)
588 {
589 return _EGL_NATIVE_PLATFORM;
590 }
591
592
593 /**
594 * Plug all the available fallback routines into the given driver's
595 * dispatch table.
596 */
597 void
598 _eglInitDriverFallbacks(_EGLDriver *drv)
599 {
600 /* If a pointer is set to NULL, then the device driver _really_ has
601 * to implement it.
602 */
603 drv->API.Initialize = NULL;
604 drv->API.Terminate = NULL;
605
606 drv->API.GetConfigs = _eglGetConfigs;
607 drv->API.ChooseConfig = _eglChooseConfig;
608 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
609
610 drv->API.CreateContext = _eglCreateContext;
611 drv->API.DestroyContext = _eglDestroyContext;
612 drv->API.MakeCurrent = _eglMakeCurrent;
613 drv->API.QueryContext = _eglQueryContext;
614
615 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
616 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
617 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
618 drv->API.DestroySurface = _eglDestroySurface;
619 drv->API.QuerySurface = _eglQuerySurface;
620 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
621 drv->API.BindTexImage = _eglBindTexImage;
622 drv->API.ReleaseTexImage = _eglReleaseTexImage;
623 drv->API.SwapInterval = _eglSwapInterval;
624 drv->API.SwapBuffers = _eglSwapBuffers;
625 drv->API.CopyBuffers = _eglCopyBuffers;
626
627 drv->API.QueryString = _eglQueryString;
628 drv->API.WaitClient = _eglWaitClient;
629 drv->API.WaitNative = _eglWaitNative;
630
631 #ifdef EGL_MESA_screen_surface
632 drv->API.ChooseModeMESA = _eglChooseModeMESA;
633 drv->API.GetModesMESA = _eglGetModesMESA;
634 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
635 drv->API.GetScreensMESA = _eglGetScreensMESA;
636 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
637 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
638 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
639 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
640 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
641 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
642 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
643 #endif /* EGL_MESA_screen_surface */
644
645 #ifdef EGL_VERSION_1_2
646 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
647 #endif /* EGL_VERSION_1_2 */
648
649 #ifdef EGL_KHR_image_base
650 drv->API.CreateImageKHR = _eglCreateImageKHR;
651 drv->API.DestroyImageKHR = _eglDestroyImageKHR;
652 #endif /* EGL_KHR_image_base */
653 }
654
655
656 /**
657 * Invoke a callback function on each EGL search path.
658 *
659 * The first argument of the callback function is the name of the search path.
660 * The second argument is the length of the name.
661 */
662 void
663 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
664 void *callback_data)
665 {
666 const char *search_path = _eglGetSearchPath();
667 _eglPreloadForEach(search_path, callback, callback_data);
668 }
669
670
671 /**
672 * Set the probe cache at the given key.
673 *
674 * A key, instead of a _EGLDriver, is used to allow the probe cache to be share
675 * by multiple drivers.
676 */
677 void
678 _eglSetProbeCache(EGLint key, const void *val)
679 {
680 EGLint idx;
681
682 for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) {
683 if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key)
684 break;
685 }
686 assert(key > 0);
687 assert(idx < NUM_PROBE_CACHE_SLOTS);
688
689 _eglProbeCache.keys[idx] = key;
690 _eglProbeCache.values[idx] = val;
691 }
692
693
694 /**
695 * Return the probe cache at the given key.
696 */
697 const void *
698 _eglGetProbeCache(EGLint key)
699 {
700 EGLint idx;
701
702 for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) {
703 if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key)
704 break;
705 }
706
707 return (idx < NUM_PROBE_CACHE_SLOTS && _eglProbeCache.keys[idx] == key) ?
708 _eglProbeCache.values[idx] : NULL;
709 }