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