egl: Add _eglPreloadDrivers.
[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
23 #if defined(_EGL_PLATFORM_X)
24 #include <dlfcn.h>
25 #include <sys/types.h>
26 #include <dirent.h>
27 #endif
28
29
30 /**
31 * Wrappers for dlopen/dlclose()
32 */
33 #if defined(_EGL_PLATFORM_WINDOWS)
34
35
36 /* XXX Need to decide how to do dynamic name lookup on Windows */
37 static const char DefaultDriverName[] = "TBD";
38
39 typedef HMODULE lib_handle;
40
41 static HMODULE
42 open_library(const char *filename)
43 {
44 return LoadLibrary(filename);
45 }
46
47 static void
48 close_library(HMODULE lib)
49 {
50 FreeLibrary(lib);
51 }
52
53
54 static const char *
55 library_suffix(void)
56 {
57 return "dll";
58 }
59
60
61 #elif defined(_EGL_PLATFORM_X)
62
63
64 static const char DefaultDriverName[] = "egl_softpipe";
65
66 typedef void * lib_handle;
67
68 static void *
69 open_library(const char *filename)
70 {
71 return dlopen(filename, RTLD_LAZY);
72 }
73
74 static void
75 close_library(void *lib)
76 {
77 dlclose(lib);
78 }
79
80
81 static const char *
82 library_suffix(void)
83 {
84 return "so";
85 }
86
87
88 #else /* _EGL_PLATFORM_NO_OS */
89
90 static const char DefaultDriverName[] = "builtin";
91
92 typedef void *lib_handle;
93
94 static INLINE void *
95 open_library(const char *filename)
96 {
97 return (void *) filename;
98 }
99
100 static INLINE void
101 close_library(void *lib)
102 {
103 }
104
105
106 static const char *
107 library_suffix(void)
108 {
109 return NULL;
110 }
111
112
113 #endif
114
115
116 /**
117 * Choose a driver for a given display.
118 * The caller may free() the returned strings.
119 */
120 static char *
121 _eglChooseDriver(_EGLDisplay *dpy, char **argsRet)
122 {
123 char *path = NULL;
124 const char *args = NULL;
125 const char *suffix = NULL;
126 const char *p;
127
128 path = getenv("EGL_DRIVER");
129 if (path)
130 path = _eglstrdup(path);
131
132 #if defined(_EGL_PLATFORM_X)
133 if (!path && dpy && dpy->NativeDisplay) {
134 /* assume (wrongly!) that the native display is a display string */
135 path = _eglSplitDisplayString((const char *) dpy->NativeDisplay, &args);
136 }
137 suffix = "so";
138 #elif defined(_EGL_PLATFORM_WINDOWS)
139 suffix = "dll";
140 #else /* _EGL_PLATFORM_NO_OS */
141 if (path) {
142 /* force the use of the default driver */
143 _eglLog(_EGL_DEBUG, "ignore EGL_DRIVER");
144 free(path);
145 path = NULL;
146 }
147 suffix = NULL;
148 #endif
149
150 if (!path)
151 path = _eglstrdup(DefaultDriverName);
152
153 /* append suffix if there isn't */
154 p = strrchr(path, '.');
155 if (!p && suffix) {
156 size_t len = strlen(path);
157 char *tmp = malloc(len + strlen(suffix) + 2);
158 if (tmp) {
159 memcpy(tmp, path, len);
160 tmp[len++] = '.';
161 tmp[len] = '\0';
162 strcat(tmp + len, suffix);
163
164 free(path);
165 path = tmp;
166 }
167 }
168
169 if (argsRet)
170 *argsRet = (args) ? _eglstrdup(args) : NULL;
171
172 return path;
173 }
174
175
176 /**
177 * Open the named driver and find its bootstrap function: _eglMain().
178 */
179 static _EGLMain_t
180 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
181 {
182 lib_handle lib;
183 _EGLMain_t mainFunc = NULL;
184 const char *error = "unknown error";
185
186 assert(driverPath);
187
188 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
189 lib = open_library(driverPath);
190
191 #if defined(_EGL_PLATFORM_WINDOWS)
192 /* XXX untested */
193 if (lib)
194 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
195 #elif defined(_EGL_PLATFORM_X)
196 if (lib) {
197 mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
198 if (!mainFunc)
199 error = dlerror();
200 }
201 else {
202 error = dlerror();
203 }
204 #else /* _EGL_PLATFORM_NO_OS */
205 /* must be the default driver name */
206 if (strcmp(driverPath, DefaultDriverName) == 0)
207 mainFunc = (_EGLMain_t) _eglMain;
208 else
209 error = "not builtin driver";
210 #endif
211
212 if (!lib) {
213 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
214 driverPath, error);
215 if (!getenv("EGL_DRIVER"))
216 _eglLog(_EGL_WARNING,
217 "The driver can be overridden by setting EGL_DRIVER");
218 return NULL;
219 }
220
221 if (!mainFunc) {
222 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
223 driverPath, error);
224 if (lib)
225 close_library(lib);
226 return NULL;
227 }
228
229 *handle = lib;
230 return mainFunc;
231 }
232
233
234 /**
235 * Load the named driver.
236 */
237 static _EGLDriver *
238 _eglLoadDriver(const char *path, const char *args)
239 {
240 _EGLMain_t mainFunc;
241 lib_handle lib;
242 _EGLDriver *drv = NULL;
243
244 mainFunc = _eglOpenLibrary(path, &lib);
245 if (!mainFunc)
246 return NULL;
247
248 drv = mainFunc(args);
249 if (!drv) {
250 if (lib)
251 close_library(lib);
252 return NULL;
253 }
254
255 if (!drv->Name) {
256 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
257 drv->Name = "UNNAMED";
258 }
259
260 drv->Path = _eglstrdup(path);
261 drv->Args = (args) ? _eglstrdup(args) : NULL;
262 if (!drv->Path || (args && !drv->Args)) {
263 if (drv->Path)
264 free((char *) drv->Path);
265 if (drv->Args)
266 free((char *) drv->Args);
267 drv->Unload(drv);
268 if (lib)
269 close_library(lib);
270 return NULL;
271 }
272
273 drv->LibHandle = lib;
274
275 return drv;
276 }
277
278
279 /**
280 * Match a display to a preloaded driver.
281 */
282 static _EGLDriver *
283 _eglMatchDriver(_EGLDisplay *dpy)
284 {
285 _EGLDriver *defaultDriver = NULL;
286 EGLint i;
287
288 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
289 _EGLDriver *drv = _eglGlobal.Drivers[i];
290
291 /* display specifies a driver */
292 if (dpy->DriverName) {
293 if (strcmp(dpy->DriverName, drv->Name) == 0)
294 return drv;
295 }
296 else if (drv->Probe) {
297 if (drv->Probe(drv, dpy))
298 return drv;
299 }
300 else {
301 if (!defaultDriver)
302 defaultDriver = drv;
303 }
304 }
305
306 return defaultDriver;
307 }
308
309
310 /**
311 * Load a driver and save it.
312 */
313 const char *
314 _eglPreloadDriver(_EGLDisplay *dpy)
315 {
316 char *path, *args;
317 _EGLDriver *drv;
318 EGLint i;
319
320 path = _eglChooseDriver(dpy, &args);
321 if (!path)
322 return NULL;
323
324 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
325 drv = _eglGlobal.Drivers[i];
326 if (strcmp(drv->Path, path) == 0) {
327 _eglLog(_EGL_DEBUG, "Driver %s is already preloaded",
328 drv->Name);
329 free(path);
330 if (args)
331 free(args);
332 return drv->Name;
333 }
334 }
335
336 drv = _eglLoadDriver(path, args);
337 if (!drv) {
338 free(path);
339 if (args)
340 free(args);
341 return NULL;
342 }
343
344 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
345
346 return drv->Name;
347 }
348
349
350 /**
351 * Open a preloaded driver.
352 */
353 _EGLDriver *
354 _eglOpenDriver(_EGLDisplay *dpy)
355 {
356 _EGLDriver *drv = _eglMatchDriver(dpy);
357 return drv;
358 }
359
360
361 /**
362 * Close a preloaded driver.
363 */
364 EGLBoolean
365 _eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy)
366 {
367 return EGL_TRUE;
368 }
369
370
371 /**
372 * Preload a user driver.
373 *
374 * A user driver can be specified by EGL_DRIVER.
375 */
376 static EGLBoolean
377 _eglPreloadUserDriver(void)
378 {
379 #if defined(_EGL_PLATFORM_X) || defined(_EGL_PLATFORM_WINDOWS)
380 _EGLDriver *drv;
381 char *env, *path;
382 const char *suffix, *p;
383
384 env = getenv("EGL_DRIVER");
385 if (!env)
386 return EGL_FALSE;
387
388 path = env;
389 suffix = library_suffix();
390
391 /* append suffix if there isn't */
392 p = strrchr(path, '.');
393 if (!p && suffix) {
394 size_t len = strlen(path);
395 char *tmp = malloc(len + strlen(suffix) + 2);
396 if (tmp) {
397 memcpy(tmp, path, len);
398 tmp[len++] = '.';
399 tmp[len] = '\0';
400 strcat(tmp + len, suffix);
401
402 path = tmp;
403 }
404 }
405
406 drv = _eglLoadDriver(path, NULL);
407 if (path != env)
408 free(path);
409 if (!drv)
410 return EGL_FALSE;
411
412 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
413
414 return EGL_TRUE;
415 #else /* _EGL_PLATFORM_X || _EGL_PLATFORM_WINDOWS */
416 return EGL_FALSE;
417 #endif
418 }
419
420
421 /**
422 * Preload display drivers.
423 *
424 * Display drivers are a set of drivers that support a certain display system.
425 * The display system may be specified by EGL_DISPLAY.
426 *
427 * FIXME This makes libEGL a memory hog if an user driver is not specified and
428 * there are many display drivers.
429 */
430 static EGLBoolean
431 _eglPreloadDisplayDrivers(void)
432 {
433 #if defined(_EGL_PLATFORM_X)
434 const char *dpy, *suffix;
435 char path[1024], prefix[32];
436 DIR *dirp;
437 struct dirent *dirent;
438
439 dpy = getenv("EGL_DISPLAY");
440 if (!dpy || !dpy[0])
441 dpy = _EGL_DEFAULT_DISPLAY;
442 if (!dpy || !dpy[0])
443 return EGL_FALSE;
444
445 snprintf(prefix, sizeof(prefix), "egl_%s_", dpy);
446 suffix = library_suffix();
447
448 dirp = opendir(_EGL_DRIVER_SEARCH_DIR);
449 if (!dirp)
450 return EGL_FALSE;
451
452 while ((dirent = readdir(dirp))) {
453 _EGLDriver *drv;
454 const char *p;
455
456 /* match the prefix */
457 if (strncmp(dirent->d_name, prefix, strlen(prefix)) != 0)
458 continue;
459
460 /* match the suffix */
461 p = strrchr(dirent->d_name, '.');
462 if ((p && !suffix) || (!p && suffix))
463 continue;
464 else if (p && suffix && strcmp(p + 1, suffix) != 0)
465 continue;
466
467 snprintf(path, sizeof(path),
468 _EGL_DRIVER_SEARCH_DIR"/%s", dirent->d_name);
469
470 drv = _eglLoadDriver(path, NULL);
471 if (drv)
472 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
473 }
474
475 closedir(dirp);
476
477 return (_eglGlobal.NumDrivers > 0);
478 #else /* _EGL_PLATFORM_X */
479 return EGL_FALSE;
480 #endif
481 }
482
483
484 /**
485 * Preload the default driver.
486 */
487 static EGLBoolean
488 _eglPreloadDefaultDriver(void)
489 {
490 _EGLDriver *drv;
491 char path[1024];
492 const char *suffix = library_suffix();
493
494 if (suffix)
495 snprintf(path, sizeof(path), "%s.%s", DefaultDriverName, suffix);
496 else
497 snprintf(path, sizeof(path), DefaultDriverName);
498
499 drv = _eglLoadDriver(path, NULL);
500 if (!drv)
501 return EGL_FALSE;
502
503 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
504
505 return EGL_TRUE;
506 }
507
508
509 /**
510 * Preload drivers.
511 *
512 * This function loads the driver modules and creates the corresponding
513 * _EGLDriver objects.
514 */
515 EGLBoolean
516 _eglPreloadDrivers(void)
517 {
518 EGLBoolean loaded;
519
520 /* already preloaded */
521 if (_eglGlobal.NumDrivers)
522 return EGL_TRUE;
523
524 loaded = (_eglPreloadUserDriver() ||
525 _eglPreloadDisplayDrivers() ||
526 _eglPreloadDefaultDriver());
527
528 return loaded;
529 }
530
531
532 /**
533 * Unload preloaded drivers.
534 */
535 void
536 _eglUnloadDrivers(void)
537 {
538 EGLint i;
539 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
540 _EGLDriver *drv = _eglGlobal.Drivers[i];
541 lib_handle handle = drv->LibHandle;
542
543 if (drv->Path)
544 free((char *) drv->Path);
545 if (drv->Args)
546 free((char *) drv->Args);
547
548 /* destroy driver */
549 if (drv->Unload)
550 drv->Unload(drv);
551
552 if (handle)
553 close_library(handle);
554 _eglGlobal.Drivers[i] = NULL;
555 }
556
557 _eglGlobal.NumDrivers = 0;
558 }
559
560
561 /**
562 * Given a display handle, return the _EGLDriver for that display.
563 */
564 _EGLDriver *
565 _eglLookupDriver(EGLDisplay dpy)
566 {
567 _EGLDisplay *d = _eglLookupDisplay(dpy);
568 if (d)
569 return d->Driver;
570 else
571 return NULL;
572 }
573
574
575 /**
576 * Plug all the available fallback routines into the given driver's
577 * dispatch table.
578 */
579 void
580 _eglInitDriverFallbacks(_EGLDriver *drv)
581 {
582 /* If a pointer is set to NULL, then the device driver _really_ has
583 * to implement it.
584 */
585 drv->API.Initialize = NULL;
586 drv->API.Terminate = NULL;
587
588 drv->API.GetConfigs = _eglGetConfigs;
589 drv->API.ChooseConfig = _eglChooseConfig;
590 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
591
592 drv->API.CreateContext = _eglCreateContext;
593 drv->API.DestroyContext = _eglDestroyContext;
594 drv->API.MakeCurrent = _eglMakeCurrent;
595 drv->API.QueryContext = _eglQueryContext;
596
597 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
598 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
599 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
600 drv->API.DestroySurface = _eglDestroySurface;
601 drv->API.QuerySurface = _eglQuerySurface;
602 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
603 drv->API.BindTexImage = _eglBindTexImage;
604 drv->API.ReleaseTexImage = _eglReleaseTexImage;
605 drv->API.SwapInterval = _eglSwapInterval;
606 drv->API.SwapBuffers = _eglSwapBuffers;
607 drv->API.CopyBuffers = _eglCopyBuffers;
608
609 drv->API.QueryString = _eglQueryString;
610 drv->API.WaitClient = _eglWaitClient;
611 drv->API.WaitNative = _eglWaitNative;
612
613 #ifdef EGL_MESA_screen_surface
614 drv->API.ChooseModeMESA = _eglChooseModeMESA;
615 drv->API.GetModesMESA = _eglGetModesMESA;
616 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
617 drv->API.GetScreensMESA = _eglGetScreensMESA;
618 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
619 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
620 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
621 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
622 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
623 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
624 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
625 #endif /* EGL_MESA_screen_surface */
626
627 #ifdef EGL_VERSION_1_2
628 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
629 #endif /* EGL_VERSION_1_2 */
630 }
631
632
633
634 /**
635 * Try to determine which EGL APIs (OpenGL, OpenGL ES, OpenVG, etc)
636 * are supported on the system by looking for standard library names.
637 */
638 EGLint
639 _eglFindAPIs(void)
640 {
641 EGLint mask = 0x0;
642 lib_handle lib;
643 #if defined(_EGL_PLATFORM_WINDOWS)
644 /* XXX not sure about these names */
645 const char *es1_libname = "libGLESv1_CM.dll";
646 const char *es2_libname = "libGLESv2.dll";
647 const char *gl_libname = "OpenGL32.dll";
648 const char *vg_libname = "libOpenVG.dll";
649 #elif defined(_EGL_PLATFORM_X)
650 const char *es1_libname = "libGLESv1_CM.so";
651 const char *es2_libname = "libGLESv2.so";
652 const char *gl_libname = "libGL.so";
653 const char *vg_libname = "libOpenVG.so";
654 #else /* _EGL_PLATFORM_NO_OS */
655 const char *es1_libname = NULL;
656 const char *es2_libname = NULL;
657 const char *gl_libname = NULL;
658 const char *vg_libname = NULL;
659 #endif
660
661 if ((lib = open_library(es1_libname))) {
662 close_library(lib);
663 mask |= EGL_OPENGL_ES_BIT;
664 }
665
666 if ((lib = open_library(es2_libname))) {
667 close_library(lib);
668 mask |= EGL_OPENGL_ES2_BIT;
669 }
670
671 if ((lib = open_library(gl_libname))) {
672 close_library(lib);
673 mask |= EGL_OPENGL_BIT;
674 }
675
676 if ((lib = open_library(vg_libname))) {
677 close_library(lib);
678 mask |= EGL_OPENVG_BIT;
679 }
680
681 return mask;
682 }