Merge branch 'master' into gallium-0.2
[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 * XXX this function is totally subject change!!!
119 *
120 *
121 * Determine/return the name of the driver to use for the given _EGLDisplay.
122 *
123 * Try to be clever and determine if nativeDisplay is an Xlib Display
124 * ptr or a string (naming a driver or screen number, etc).
125 *
126 * If the first character is ':' we interpret it as a screen or card index
127 * number (i.e. ":0" or ":1", etc)
128 * Else if the first character is '!' we interpret it as specific driver name
129 * (i.e. "!r200" or "!i830".
130 *
131 * Whatever follows ':' is copied and put into dpy->DriverArgs.
132 *
133 * The caller may free() the returned string.
134 */
135 const char *
136 _eglChooseDriver(_EGLDisplay *dpy)
137 {
138 /* Under Windows, the NativeDisplay is an HDC handle, therefore */
139 /* it can't be interpreted as a string or a pointer. */
140 #if defined(_EGL_PLATFORM_WINDOWS)
141 const char *displayString = NULL;
142 #else
143 const char *displayString = (const char *) dpy->NativeDisplay;
144 #endif
145 const char *driverName = NULL;
146
147 (void) DefaultDriverName;
148
149 #if defined(_EGL_PLATFORM_X)
150 /* First, if the EGL_DRIVER env var is set, use that */
151 driverName = getenv("EGL_DRIVER");
152 if (driverName)
153 return _eglstrdup(driverName);
154 #endif
155
156 #if 0
157 if (!displayString) {
158 /* choose a default */
159 displayString = DefaultDriverName;
160 }
161 #endif
162 /* extract default DriverArgs = whatever follows ':' */
163 if (displayString &&
164 (displayString[0] == '!' ||
165 displayString[0] == ':')) {
166 const char *args = strchr(displayString, ':');
167 if (args)
168 dpy->DriverArgs = _eglstrdup(args + 1);
169 }
170
171 /* determine driver name now */
172 if (displayString && displayString[0] == ':' &&
173 (displayString[1] >= '0' && displayString[1] <= '9') &&
174 !displayString[2]) {
175 int card = atoi(displayString + 1);
176 driverName = _eglChooseDRMDriver(card);
177 }
178 else if (displayString && displayString[0] == '!') {
179 /* use user-specified driver name */
180 driverName = _eglstrdup(displayString + 1);
181 /* truncate driverName at ':' if present */
182 {
183 char *args = strchr(driverName, ':');
184 if (args) {
185 *args = 0;
186 }
187 }
188 }
189 else
190 {
191 /* NativeDisplay is not a string! */
192 #if defined(_EGL_PLATFORM_X)
193 driverName = _xeglChooseDriver(dpy);
194 #else
195 driverName = DefaultDriverName;
196 #endif
197 }
198
199 return driverName;
200 }
201
202
203 /**
204 * Open/load the named driver and call its bootstrap function: _eglMain().
205 * By the time this function is called, the dpy->DriverName should have
206 * been determined.
207 *
208 * \return new _EGLDriver object.
209 */
210 _EGLDriver *
211 _eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args)
212 {
213 _EGLDriver *drv;
214 _EGLMain_t mainFunc;
215 lib_handle lib;
216 char driverFilename[1000];
217
218 assert(driverName);
219
220 #if defined(_EGL_PLATFORM_WINDOWS)
221 /* Use static linking on Windows for now */
222 #ifdef WINDOWS_STATIC_LINK
223 lib = 0;
224 mainFunc = (_EGLMain_t)_eglMain;
225 #else
226 /* XXX untested */
227 sprintf(driverFilename, "%s.dll", driverName);
228 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
229 lib = open_library(driverFilename);
230 if (!lib) {
231 _eglLog(_EGL_WARNING, "Could not open %s",
232 driverFilename);
233 return NULL;
234 }
235 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
236 #endif
237 #elif defined(_EGL_PLATFORM_X)
238 /* XXX also prepend a directory path??? */
239 sprintf(driverFilename, "%s.so", driverName);
240 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
241 lib = open_library(driverFilename);
242 if (!lib) {
243 _eglLog(_EGL_WARNING, "Could not open %s (%s)",
244 driverFilename, dlerror());
245 return NULL;
246 }
247 mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
248 #endif
249
250 if (!mainFunc) {
251 _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename);
252 close_library(lib);
253 return NULL;
254 }
255
256 drv = mainFunc(dpy, args);
257 if (!drv) {
258 close_library(lib);
259 return NULL;
260 }
261
262 /* with a recurvise open you want the inner most handle */
263 if (!drv->LibHandle) {
264 drv->LibHandle = lib;
265 }
266 else {
267 close_library(lib);
268 }
269
270 /* update the global notion of supported APIs */
271 _eglGlobal.ClientAPIsMask |= drv->ClientAPIsMask;
272
273 _eglSaveDriver(drv);
274
275 return drv;
276 }
277
278
279 EGLBoolean
280 _eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy)
281 {
282 void *handle = drv->LibHandle;
283 EGLBoolean b;
284
285 _eglLog(_EGL_DEBUG, "Closing %s", drv->Name);
286
287 /*
288 * XXX check for currently bound context/surfaces and delete them?
289 */
290
291 b = drv->API.Terminate(drv, dpy);
292
293 close_library(handle);
294
295 return b;
296 }
297
298
299 /**
300 * Save the given driver pointer in the list of all known drivers.
301 */
302 void
303 _eglSaveDriver(_EGLDriver *drv)
304 {
305 _eglGlobal.Drivers[ _eglGlobal.NumDrivers++ ] = drv;
306 }
307
308
309 /**
310 * Given a display handle, return the _EGLDriver for that display.
311 */
312 _EGLDriver *
313 _eglLookupDriver(EGLDisplay dpy)
314 {
315 _EGLDisplay *d = _eglLookupDisplay(dpy);
316 if (d)
317 return d->Driver;
318 else
319 return NULL;
320 }
321
322
323 /**
324 * Plug all the available fallback routines into the given driver's
325 * dispatch table.
326 */
327 void
328 _eglInitDriverFallbacks(_EGLDriver *drv)
329 {
330 /* If a pointer is set to NULL, then the device driver _really_ has
331 * to implement it.
332 */
333 drv->API.Initialize = NULL;
334 drv->API.Terminate = NULL;
335
336 drv->API.GetConfigs = _eglGetConfigs;
337 drv->API.ChooseConfig = _eglChooseConfig;
338 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
339
340 drv->API.CreateContext = _eglCreateContext;
341 drv->API.DestroyContext = _eglDestroyContext;
342 drv->API.MakeCurrent = _eglMakeCurrent;
343 drv->API.QueryContext = _eglQueryContext;
344
345 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
346 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
347 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
348 drv->API.DestroySurface = _eglDestroySurface;
349 drv->API.QuerySurface = _eglQuerySurface;
350 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
351 drv->API.BindTexImage = _eglBindTexImage;
352 drv->API.ReleaseTexImage = _eglReleaseTexImage;
353 drv->API.SwapInterval = _eglSwapInterval;
354 drv->API.SwapBuffers = _eglSwapBuffers;
355 drv->API.CopyBuffers = _eglCopyBuffers;
356
357 drv->API.QueryString = _eglQueryString;
358 drv->API.WaitGL = _eglWaitGL;
359 drv->API.WaitNative = _eglWaitNative;
360
361 #ifdef EGL_MESA_screen_surface
362 drv->API.ChooseModeMESA = _eglChooseModeMESA;
363 drv->API.GetModesMESA = _eglGetModesMESA;
364 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
365 drv->API.GetScreensMESA = _eglGetScreensMESA;
366 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
367 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
368 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
369 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
370 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
371 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
372 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
373 #endif /* EGL_MESA_screen_surface */
374
375 #ifdef EGL_VERSION_1_2
376 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
377 #endif /* EGL_VERSION_1_2 */
378 }
379
380
381
382 /**
383 * Try to determine which EGL APIs (OpenGL, OpenGL ES, OpenVG, etc)
384 * are supported on the system by looking for standard library names.
385 */
386 EGLint
387 _eglFindAPIs(void)
388 {
389 EGLint mask = 0x0;
390 lib_handle lib;
391 #if defined(_EGL_PLATFORM_WINDOWS)
392 /* XXX not sure about these names */
393 const char *es1_libname = "libGLESv1_CM.dll";
394 const char *es2_libname = "libGLESv2.dll";
395 const char *gl_libname = "OpenGL32.dll";
396 const char *vg_libname = "libOpenVG.dll";
397 #elif defined(_EGL_PLATFORM_X)
398 const char *es1_libname = "libGLESv1_CM.so";
399 const char *es2_libname = "libGLESv2.so";
400 const char *gl_libname = "libGL.so";
401 const char *vg_libname = "libOpenVG.so";
402 #endif
403
404 if ((lib = open_library(es1_libname))) {
405 close_library(lib);
406 mask |= EGL_OPENGL_ES_BIT;
407 }
408
409 if ((lib = open_library(es2_libname))) {
410 close_library(lib);
411 mask |= EGL_OPENGL_ES2_BIT;
412 }
413
414 if ((lib = open_library(gl_libname))) {
415 close_library(lib);
416 mask |= EGL_OPENGL_BIT;
417 }
418
419 if ((lib = open_library(vg_libname))) {
420 close_library(lib);
421 mask |= EGL_OPENVG_BIT;
422 }
423
424 return mask;
425 }