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