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