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