egl: Improve driver matching.
[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_POSIX)
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_POSIX)
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 * Open the named driver and find its bootstrap function: _eglMain().
118 */
119 static _EGLMain_t
120 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
121 {
122 lib_handle lib;
123 _EGLMain_t mainFunc = NULL;
124 const char *error = "unknown error";
125
126 assert(driverPath);
127
128 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
129 lib = open_library(driverPath);
130
131 #if defined(_EGL_PLATFORM_WINDOWS)
132 /* XXX untested */
133 if (lib)
134 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
135 #elif defined(_EGL_PLATFORM_POSIX)
136 if (lib) {
137 mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
138 if (!mainFunc)
139 error = dlerror();
140 }
141 else {
142 error = dlerror();
143 }
144 #else /* _EGL_PLATFORM_NO_OS */
145 /* must be the default driver name */
146 if (strcmp(driverPath, DefaultDriverName) == 0)
147 mainFunc = (_EGLMain_t) _eglMain;
148 else
149 error = "not builtin driver";
150 #endif
151
152 if (!lib) {
153 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
154 driverPath, error);
155 if (!getenv("EGL_DRIVER"))
156 _eglLog(_EGL_WARNING,
157 "The driver can be overridden by setting EGL_DRIVER");
158 return NULL;
159 }
160
161 if (!mainFunc) {
162 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
163 driverPath, error);
164 if (lib)
165 close_library(lib);
166 return NULL;
167 }
168
169 *handle = lib;
170 return mainFunc;
171 }
172
173
174 /**
175 * Load the named driver.
176 */
177 static _EGLDriver *
178 _eglLoadDriver(const char *path, const char *args)
179 {
180 _EGLMain_t mainFunc;
181 lib_handle lib;
182 _EGLDriver *drv = NULL;
183
184 mainFunc = _eglOpenLibrary(path, &lib);
185 if (!mainFunc)
186 return NULL;
187
188 drv = mainFunc(args);
189 if (!drv) {
190 if (lib)
191 close_library(lib);
192 return NULL;
193 }
194
195 if (!drv->Name) {
196 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
197 drv->Name = "UNNAMED";
198 }
199
200 drv->Path = _eglstrdup(path);
201 drv->Args = (args) ? _eglstrdup(args) : NULL;
202 if (!drv->Path || (args && !drv->Args)) {
203 if (drv->Path)
204 free((char *) drv->Path);
205 if (drv->Args)
206 free((char *) drv->Args);
207 drv->Unload(drv);
208 if (lib)
209 close_library(lib);
210 return NULL;
211 }
212
213 drv->LibHandle = lib;
214
215 return drv;
216 }
217
218
219 /**
220 * Match a display to a preloaded driver.
221 *
222 * The matching is done by finding the driver with the highest score.
223 */
224 static _EGLDriver *
225 _eglMatchDriver(_EGLDisplay *dpy)
226 {
227 _EGLDriver *best_drv = NULL;
228 EGLint best_score = -1, i;
229
230 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
231 _EGLDriver *drv = _eglGlobal.Drivers[i];
232 EGLint score;
233
234 score = (drv->Probe) ? drv->Probe(drv, dpy) : 0;
235 if (score > best_score) {
236 if (best_drv) {
237 _eglLog(_EGL_DEBUG, "driver %s has higher score than %s",
238 drv->Name, best_drv->Name);
239 }
240
241 best_drv = drv;
242 best_score = score;
243 /* perfect match */
244 if (score >= 100)
245 break;
246 }
247 }
248
249 return best_drv;
250 }
251
252
253 /**
254 * Open a preloaded driver.
255 */
256 _EGLDriver *
257 _eglOpenDriver(_EGLDisplay *dpy)
258 {
259 _EGLDriver *drv = _eglMatchDriver(dpy);
260 return drv;
261 }
262
263
264 /**
265 * Close a preloaded driver.
266 */
267 EGLBoolean
268 _eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy)
269 {
270 return EGL_TRUE;
271 }
272
273
274 /**
275 * Preload a user driver.
276 *
277 * A user driver can be specified by EGL_DRIVER.
278 */
279 static EGLBoolean
280 _eglPreloadUserDriver(void)
281 {
282 #if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS)
283 _EGLDriver *drv;
284 char *env, *path;
285 const char *suffix, *p;
286
287 env = getenv("EGL_DRIVER");
288 if (!env)
289 return EGL_FALSE;
290
291 path = env;
292 suffix = library_suffix();
293
294 /* append suffix if there isn't */
295 p = strrchr(path, '.');
296 if (!p && suffix) {
297 size_t len = strlen(path);
298 char *tmp = malloc(len + strlen(suffix) + 2);
299 if (tmp) {
300 memcpy(tmp, path, len);
301 tmp[len++] = '.';
302 tmp[len] = '\0';
303 strcat(tmp + len, suffix);
304
305 path = tmp;
306 }
307 }
308
309 drv = _eglLoadDriver(path, NULL);
310 if (path != env)
311 free(path);
312 if (!drv)
313 return EGL_FALSE;
314
315 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
316
317 return EGL_TRUE;
318 #else /* _EGL_PLATFORM_POSIX || _EGL_PLATFORM_WINDOWS */
319 return EGL_FALSE;
320 #endif
321 }
322
323
324 /**
325 * Preload display drivers.
326 *
327 * Display drivers are a set of drivers that support a certain display system.
328 * The display system may be specified by EGL_DISPLAY.
329 *
330 * FIXME This makes libEGL a memory hog if an user driver is not specified and
331 * there are many display drivers.
332 */
333 static EGLBoolean
334 _eglPreloadDisplayDrivers(void)
335 {
336 #if defined(_EGL_PLATFORM_POSIX)
337 const char *dpy, *suffix;
338 char path[1024], prefix[32];
339 DIR *dirp;
340 struct dirent *dirent;
341
342 dpy = getenv("EGL_DISPLAY");
343 if (!dpy || !dpy[0])
344 dpy = _EGL_DEFAULT_DISPLAY;
345 if (!dpy || !dpy[0])
346 return EGL_FALSE;
347
348 snprintf(prefix, sizeof(prefix), "egl_%s_", dpy);
349 suffix = library_suffix();
350
351 dirp = opendir(_EGL_DRIVER_SEARCH_DIR);
352 if (!dirp)
353 return EGL_FALSE;
354
355 while ((dirent = readdir(dirp))) {
356 _EGLDriver *drv;
357 const char *p;
358
359 /* match the prefix */
360 if (strncmp(dirent->d_name, prefix, strlen(prefix)) != 0)
361 continue;
362
363 /* match the suffix */
364 p = strrchr(dirent->d_name, '.');
365 if ((p && !suffix) || (!p && suffix))
366 continue;
367 else if (p && suffix && strcmp(p + 1, suffix) != 0)
368 continue;
369
370 snprintf(path, sizeof(path),
371 _EGL_DRIVER_SEARCH_DIR"/%s", dirent->d_name);
372
373 drv = _eglLoadDriver(path, NULL);
374 if (drv)
375 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
376 }
377
378 closedir(dirp);
379
380 return (_eglGlobal.NumDrivers > 0);
381 #else /* _EGL_PLATFORM_POSIX */
382 return EGL_FALSE;
383 #endif
384 }
385
386
387 /**
388 * Preload the default driver.
389 */
390 static EGLBoolean
391 _eglPreloadDefaultDriver(void)
392 {
393 _EGLDriver *drv;
394 char path[1024];
395 const char *suffix = library_suffix();
396
397 if (suffix)
398 snprintf(path, sizeof(path), "%s.%s", DefaultDriverName, suffix);
399 else
400 snprintf(path, sizeof(path), DefaultDriverName);
401
402 drv = _eglLoadDriver(path, NULL);
403 if (!drv)
404 return EGL_FALSE;
405
406 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
407
408 return EGL_TRUE;
409 }
410
411
412 /**
413 * Preload drivers.
414 *
415 * This function loads the driver modules and creates the corresponding
416 * _EGLDriver objects.
417 */
418 EGLBoolean
419 _eglPreloadDrivers(void)
420 {
421 EGLBoolean loaded;
422
423 /* already preloaded */
424 if (_eglGlobal.NumDrivers)
425 return EGL_TRUE;
426
427 loaded = (_eglPreloadUserDriver() ||
428 _eglPreloadDisplayDrivers() ||
429 _eglPreloadDefaultDriver());
430
431 return loaded;
432 }
433
434
435 /**
436 * Unload preloaded drivers.
437 */
438 void
439 _eglUnloadDrivers(void)
440 {
441 EGLint i;
442 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
443 _EGLDriver *drv = _eglGlobal.Drivers[i];
444 lib_handle handle = drv->LibHandle;
445
446 if (drv->Path)
447 free((char *) drv->Path);
448 if (drv->Args)
449 free((char *) drv->Args);
450
451 /* destroy driver */
452 if (drv->Unload)
453 drv->Unload(drv);
454
455 if (handle)
456 close_library(handle);
457 _eglGlobal.Drivers[i] = NULL;
458 }
459
460 _eglGlobal.NumDrivers = 0;
461 }
462
463
464 /**
465 * Plug all the available fallback routines into the given driver's
466 * dispatch table.
467 */
468 void
469 _eglInitDriverFallbacks(_EGLDriver *drv)
470 {
471 /* If a pointer is set to NULL, then the device driver _really_ has
472 * to implement it.
473 */
474 drv->API.Initialize = NULL;
475 drv->API.Terminate = NULL;
476
477 drv->API.GetConfigs = _eglGetConfigs;
478 drv->API.ChooseConfig = _eglChooseConfig;
479 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
480
481 drv->API.CreateContext = _eglCreateContext;
482 drv->API.DestroyContext = _eglDestroyContext;
483 drv->API.MakeCurrent = _eglMakeCurrent;
484 drv->API.QueryContext = _eglQueryContext;
485
486 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
487 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
488 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
489 drv->API.DestroySurface = _eglDestroySurface;
490 drv->API.QuerySurface = _eglQuerySurface;
491 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
492 drv->API.BindTexImage = _eglBindTexImage;
493 drv->API.ReleaseTexImage = _eglReleaseTexImage;
494 drv->API.SwapInterval = _eglSwapInterval;
495 drv->API.SwapBuffers = _eglSwapBuffers;
496 drv->API.CopyBuffers = _eglCopyBuffers;
497
498 drv->API.QueryString = _eglQueryString;
499 drv->API.WaitClient = _eglWaitClient;
500 drv->API.WaitNative = _eglWaitNative;
501
502 #ifdef EGL_MESA_screen_surface
503 drv->API.ChooseModeMESA = _eglChooseModeMESA;
504 drv->API.GetModesMESA = _eglGetModesMESA;
505 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
506 drv->API.GetScreensMESA = _eglGetScreensMESA;
507 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
508 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
509 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
510 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
511 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
512 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
513 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
514 #endif /* EGL_MESA_screen_surface */
515
516 #ifdef EGL_VERSION_1_2
517 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
518 #endif /* EGL_VERSION_1_2 */
519 }
520
521
522
523 /**
524 * Try to determine which EGL APIs (OpenGL, OpenGL ES, OpenVG, etc)
525 * are supported on the system by looking for standard library names.
526 */
527 EGLint
528 _eglFindAPIs(void)
529 {
530 EGLint mask = 0x0;
531 lib_handle lib;
532 #if defined(_EGL_PLATFORM_WINDOWS)
533 /* XXX not sure about these names */
534 const char *es1_libname = "libGLESv1_CM.dll";
535 const char *es2_libname = "libGLESv2.dll";
536 const char *gl_libname = "OpenGL32.dll";
537 const char *vg_libname = "libOpenVG.dll";
538 #elif defined(_EGL_PLATFORM_POSIX)
539 const char *es1_libname = "libGLESv1_CM.so";
540 const char *es2_libname = "libGLESv2.so";
541 const char *gl_libname = "libGL.so";
542 const char *vg_libname = "libOpenVG.so";
543 #else /* _EGL_PLATFORM_NO_OS */
544 const char *es1_libname = NULL;
545 const char *es2_libname = NULL;
546 const char *gl_libname = NULL;
547 const char *vg_libname = NULL;
548 #endif
549
550 if ((lib = open_library(es1_libname))) {
551 close_library(lib);
552 mask |= EGL_OPENGL_ES_BIT;
553 }
554
555 if ((lib = open_library(es2_libname))) {
556 close_library(lib);
557 mask |= EGL_OPENGL_ES2_BIT;
558 }
559
560 if ((lib = open_library(gl_libname))) {
561 close_library(lib);
562 mask |= EGL_OPENGL_BIT;
563 }
564
565 if ((lib = open_library(vg_libname))) {
566 close_library(lib);
567 mask |= EGL_OPENVG_BIT;
568 }
569
570 return mask;
571 }