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