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