Merge branch 'mesa_7_6_branch' of git+ssh://agd5f@git.freedesktop.org/git/mesa/mesa
[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 #endif
26
27
28 /**
29 * Wrappers for dlopen/dlclose()
30 */
31 #if defined(_EGL_PLATFORM_WINDOWS)
32
33
34 /* XXX Need to decide how to do dynamic name lookup on Windows */
35 static const char DefaultDriverName[] = "TBD";
36
37 typedef HMODULE lib_handle;
38
39 static HMODULE
40 open_library(const char *filename)
41 {
42 return LoadLibrary(filename);
43 }
44
45 static void
46 close_library(HMODULE lib)
47 {
48 FreeLibrary(lib);
49 }
50
51
52 #elif defined(_EGL_PLATFORM_X)
53
54
55 static const char DefaultDriverName[] = "egl_softpipe";
56
57 typedef void * lib_handle;
58
59 static void *
60 open_library(const char *filename)
61 {
62 return dlopen(filename, RTLD_LAZY);
63 }
64
65 static void
66 close_library(void *lib)
67 {
68 dlclose(lib);
69 }
70
71 #else /* _EGL_PLATFORM_NO_OS */
72
73 static const char DefaultDriverName[] = "builtin";
74
75 typedef void *lib_handle;
76
77 static INLINE void *
78 open_library(const char *filename)
79 {
80 return (void *) filename;
81 }
82
83 static INLINE void
84 close_library(void *lib)
85 {
86 }
87
88
89 #endif
90
91
92 /**
93 * Choose a driver for a given display.
94 * The caller may free() the returned strings.
95 */
96 static char *
97 _eglChooseDriver(_EGLDisplay *dpy, char **argsRet)
98 {
99 char *path = NULL;
100 const char *args = NULL;
101 const char *suffix = NULL;
102 const char *p;
103
104 path = getenv("EGL_DRIVER");
105 if (path)
106 path = _eglstrdup(path);
107
108 #if defined(_EGL_PLATFORM_X)
109 if (!path && dpy && dpy->NativeDisplay) {
110 /* assume (wrongly!) that the native display is a display string */
111 path = _eglSplitDisplayString((const char *) dpy->NativeDisplay, &args);
112 }
113 suffix = "so";
114 #elif defined(_EGL_PLATFORM_WINDOWS)
115 suffix = "dll";
116 #else /* _EGL_PLATFORM_NO_OS */
117 if (path) {
118 /* force the use of the default driver */
119 _eglLog(_EGL_DEBUG, "ignore EGL_DRIVER");
120 free(path);
121 path = NULL;
122 }
123 suffix = NULL;
124 #endif
125
126 if (!path)
127 path = _eglstrdup(DefaultDriverName);
128
129 /* append suffix if there isn't */
130 p = strrchr(path, '.');
131 if (!p && suffix) {
132 size_t len = strlen(path);
133 char *tmp = malloc(len + strlen(suffix) + 2);
134 if (tmp) {
135 memcpy(tmp, path, len);
136 tmp[len++] = '.';
137 tmp[len] = '\0';
138 strcat(tmp + len, suffix);
139
140 free(path);
141 path = tmp;
142 }
143 }
144
145 if (argsRet)
146 *argsRet = (args) ? _eglstrdup(args) : NULL;
147
148 return path;
149 }
150
151
152 /**
153 * Open the named driver and find its bootstrap function: _eglMain().
154 */
155 static _EGLMain_t
156 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
157 {
158 lib_handle lib;
159 _EGLMain_t mainFunc = NULL;
160 const char *error = "unknown error";
161
162 assert(driverPath);
163
164 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
165 lib = open_library(driverPath);
166
167 #if defined(_EGL_PLATFORM_WINDOWS)
168 /* XXX untested */
169 if (lib)
170 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
171 #elif defined(_EGL_PLATFORM_X)
172 if (lib) {
173 mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
174 if (!mainFunc)
175 error = dlerror();
176 }
177 else {
178 error = dlerror();
179 }
180 #else /* _EGL_PLATFORM_NO_OS */
181 /* must be the default driver name */
182 if (strcmp(driverPath, DefaultDriverName) == 0)
183 mainFunc = (_EGLMain_t) _eglMain;
184 else
185 error = "not builtin driver";
186 #endif
187
188 if (!lib) {
189 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
190 driverPath, error);
191 if (!getenv("EGL_DRIVER"))
192 _eglLog(_EGL_WARNING,
193 "The driver can be overridden by setting EGL_DRIVER");
194 return NULL;
195 }
196
197 if (!mainFunc) {
198 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
199 driverPath, error);
200 if (lib)
201 close_library(lib);
202 return NULL;
203 }
204
205 *handle = lib;
206 return mainFunc;
207 }
208
209
210 /**
211 * Load the named driver. The path and args passed will be
212 * owned by the driver and freed.
213 */
214 static _EGLDriver *
215 _eglLoadDriver(char *path, char *args)
216 {
217 _EGLMain_t mainFunc;
218 lib_handle lib;
219 _EGLDriver *drv = NULL;
220
221 mainFunc = _eglOpenLibrary(path, &lib);
222 if (!mainFunc)
223 return NULL;
224
225 drv = mainFunc(args);
226 if (!drv) {
227 if (lib)
228 close_library(lib);
229 return NULL;
230 }
231
232 if (!drv->Name) {
233 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
234 drv->Name = "UNNAMED";
235 }
236
237 drv->Path = path;
238 drv->Args = args;
239 drv->LibHandle = lib;
240
241 return drv;
242 }
243
244
245 /**
246 * Match a display to a preloaded driver.
247 */
248 static _EGLDriver *
249 _eglMatchDriver(_EGLDisplay *dpy)
250 {
251 _EGLDriver *defaultDriver = NULL;
252 EGLint i;
253
254 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
255 _EGLDriver *drv = _eglGlobal.Drivers[i];
256
257 /* display specifies a driver */
258 if (dpy->DriverName) {
259 if (strcmp(dpy->DriverName, drv->Name) == 0)
260 return drv;
261 }
262 else if (drv->Probe) {
263 if (drv->Probe(drv, dpy))
264 return drv;
265 }
266 else {
267 if (!defaultDriver)
268 defaultDriver = drv;
269 }
270 }
271
272 return defaultDriver;
273 }
274
275
276 /**
277 * Load a driver and save it.
278 */
279 const char *
280 _eglPreloadDriver(_EGLDisplay *dpy)
281 {
282 char *path, *args;
283 _EGLDriver *drv;
284 EGLint i;
285
286 path = _eglChooseDriver(dpy, &args);
287 if (!path)
288 return NULL;
289
290 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
291 drv = _eglGlobal.Drivers[i];
292 if (strcmp(drv->Path, path) == 0) {
293 _eglLog(_EGL_DEBUG, "Driver %s is already preloaded",
294 drv->Name);
295 free(path);
296 if (args)
297 free(args);
298 return drv->Name;
299 }
300 }
301
302 drv = _eglLoadDriver(path, args);
303 if (!drv)
304 return NULL;
305
306 _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
307
308 return drv->Name;
309 }
310
311
312 /**
313 * Open a preloaded driver.
314 */
315 _EGLDriver *
316 _eglOpenDriver(_EGLDisplay *dpy)
317 {
318 _EGLDriver *drv = _eglMatchDriver(dpy);
319 return drv;
320 }
321
322
323 /**
324 * Close a preloaded driver.
325 */
326 EGLBoolean
327 _eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy)
328 {
329 return EGL_TRUE;
330 }
331
332
333 /**
334 * Unload preloaded drivers.
335 */
336 void
337 _eglUnloadDrivers(void)
338 {
339 EGLint i;
340 for (i = 0; i < _eglGlobal.NumDrivers; i++) {
341 _EGLDriver *drv = _eglGlobal.Drivers[i];
342 lib_handle handle = drv->LibHandle;
343
344 if (drv->Path)
345 free((char *) drv->Path);
346 if (drv->Args)
347 free((char *) drv->Args);
348
349 /* destroy driver */
350 if (drv->Unload)
351 drv->Unload(drv);
352
353 if (handle)
354 close_library(handle);
355 _eglGlobal.Drivers[i] = NULL;
356 }
357
358 _eglGlobal.NumDrivers = 0;
359 }
360
361
362 /**
363 * Given a display handle, return the _EGLDriver for that display.
364 */
365 _EGLDriver *
366 _eglLookupDriver(EGLDisplay dpy)
367 {
368 _EGLDisplay *d = _eglLookupDisplay(dpy);
369 if (d)
370 return d->Driver;
371 else
372 return NULL;
373 }
374
375
376 /**
377 * Plug all the available fallback routines into the given driver's
378 * dispatch table.
379 */
380 void
381 _eglInitDriverFallbacks(_EGLDriver *drv)
382 {
383 /* If a pointer is set to NULL, then the device driver _really_ has
384 * to implement it.
385 */
386 drv->API.Initialize = NULL;
387 drv->API.Terminate = NULL;
388
389 drv->API.GetConfigs = _eglGetConfigs;
390 drv->API.ChooseConfig = _eglChooseConfig;
391 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
392
393 drv->API.CreateContext = _eglCreateContext;
394 drv->API.DestroyContext = _eglDestroyContext;
395 drv->API.MakeCurrent = _eglMakeCurrent;
396 drv->API.QueryContext = _eglQueryContext;
397
398 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
399 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
400 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
401 drv->API.DestroySurface = _eglDestroySurface;
402 drv->API.QuerySurface = _eglQuerySurface;
403 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
404 drv->API.BindTexImage = _eglBindTexImage;
405 drv->API.ReleaseTexImage = _eglReleaseTexImage;
406 drv->API.SwapInterval = _eglSwapInterval;
407 drv->API.SwapBuffers = _eglSwapBuffers;
408 drv->API.CopyBuffers = _eglCopyBuffers;
409
410 drv->API.QueryString = _eglQueryString;
411 drv->API.WaitClient = _eglWaitClient;
412 drv->API.WaitNative = _eglWaitNative;
413
414 #ifdef EGL_MESA_screen_surface
415 drv->API.ChooseModeMESA = _eglChooseModeMESA;
416 drv->API.GetModesMESA = _eglGetModesMESA;
417 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
418 drv->API.GetScreensMESA = _eglGetScreensMESA;
419 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
420 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
421 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
422 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
423 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
424 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
425 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
426 #endif /* EGL_MESA_screen_surface */
427
428 #ifdef EGL_VERSION_1_2
429 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
430 #endif /* EGL_VERSION_1_2 */
431 }
432
433
434
435 /**
436 * Try to determine which EGL APIs (OpenGL, OpenGL ES, OpenVG, etc)
437 * are supported on the system by looking for standard library names.
438 */
439 EGLint
440 _eglFindAPIs(void)
441 {
442 EGLint mask = 0x0;
443 lib_handle lib;
444 #if defined(_EGL_PLATFORM_WINDOWS)
445 /* XXX not sure about these names */
446 const char *es1_libname = "libGLESv1_CM.dll";
447 const char *es2_libname = "libGLESv2.dll";
448 const char *gl_libname = "OpenGL32.dll";
449 const char *vg_libname = "libOpenVG.dll";
450 #elif defined(_EGL_PLATFORM_X)
451 const char *es1_libname = "libGLESv1_CM.so";
452 const char *es2_libname = "libGLESv2.so";
453 const char *gl_libname = "libGL.so";
454 const char *vg_libname = "libOpenVG.so";
455 #else /* _EGL_PLATFORM_NO_OS */
456 const char *es1_libname = NULL;
457 const char *es2_libname = NULL;
458 const char *gl_libname = NULL;
459 const char *vg_libname = NULL;
460 #endif
461
462 if ((lib = open_library(es1_libname))) {
463 close_library(lib);
464 mask |= EGL_OPENGL_ES_BIT;
465 }
466
467 if ((lib = open_library(es2_libname))) {
468 close_library(lib);
469 mask |= EGL_OPENGL_ES2_BIT;
470 }
471
472 if ((lib = open_library(gl_libname))) {
473 close_library(lib);
474 mask |= EGL_OPENGL_BIT;
475 }
476
477 if ((lib = open_library(vg_libname))) {
478 close_library(lib);
479 mask |= EGL_OPENVG_BIT;
480 }
481
482 return mask;
483 }