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