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