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