egl: use RTLD_LAZY
[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 /* XXX to do */
28 #elif defined(_EGL_PLATFORM_WINCE)
29 /* XXX to do */
30 #endif
31
32
33 static const char *DefaultDriverName = ":0";
34 static const char *SysFS = "/sys/class";
35
36
37
38
39 /**
40 * Given a card number, use sysfs to determine the DRI driver name.
41 */
42 const char *
43 _eglChooseDRMDriver(int card)
44 {
45 #if 0
46 return _eglstrdup("libEGLdri");
47 #else
48 char path[2000], driverName[2000];
49 FILE *f;
50 int length;
51
52 snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", SysFS, card);
53
54 f = fopen(path, "r");
55 if (!f)
56 return NULL;
57
58 fgets(driverName, sizeof(driverName), f);
59 fclose(f);
60
61 if ((length = strlen(driverName)) > 1) {
62 /* remove the trailing newline from sysfs */
63 driverName[length - 1] = '\0';
64 strncat(driverName, "_dri", sizeof(driverName));
65 return _eglstrdup(driverName);
66 }
67 else {
68 return NULL;
69 }
70 #endif
71 }
72
73
74 /**
75 * XXX this function is totally subject change!!!
76 *
77 *
78 * Determine/return the name of the driver to use for the given _EGLDisplay.
79 *
80 * Try to be clever and determine if nativeDisplay is an Xlib Display
81 * ptr or a string (naming a driver or screen number, etc).
82 *
83 * If the first character is ':' we interpret it as a screen or card index
84 * number (i.e. ":0" or ":1", etc)
85 * Else if the first character is '!' we interpret it as specific driver name
86 * (i.e. "!r200" or "!i830".
87 *
88 * Whatever follows ':' is copied and put into dpy->DriverArgs.
89 *
90 * The caller may free() the returned string.
91 */
92 const char *
93 _eglChooseDriver(_EGLDisplay *dpy)
94 {
95 const char *displayString = (const char *) dpy->NativeDisplay;
96 const char *driverName = NULL;
97
98 (void) DefaultDriverName;
99
100 /* First, if the EGL_DRIVER env var is set, use that */
101 driverName = getenv("EGL_DRIVER");
102 if (driverName)
103 return _eglstrdup(driverName);
104
105 #if 0
106 if (!displayString) {
107 /* choose a default */
108 displayString = DefaultDriverName;
109 }
110 #endif
111 /* extract default DriverArgs = whatever follows ':' */
112 if (displayString &&
113 (displayString[0] == '!' ||
114 displayString[0] == ':')) {
115 const char *args = strchr(displayString, ':');
116 if (args)
117 dpy->DriverArgs = _eglstrdup(args + 1);
118 }
119
120 /* determine driver name now */
121 if (displayString && displayString[0] == ':' &&
122 (displayString[1] >= '0' && displayString[1] <= '9') &&
123 !displayString[2]) {
124 int card = atoi(displayString + 1);
125 driverName = _eglChooseDRMDriver(card);
126 }
127 else if (displayString && displayString[0] == '!') {
128 /* use user-specified driver name */
129 driverName = _eglstrdup(displayString + 1);
130 /* truncate driverName at ':' if present */
131 {
132 char *args = strchr(driverName, ':');
133 if (args) {
134 *args = 0;
135 }
136 }
137 }
138 else {
139 /* NativeDisplay is not a string! */
140 #if defined(_EGL_PLATFORM_X)
141 driverName = _xeglChooseDriver(dpy);
142 #elif defined(_EGL_PLATFORM_WINDOWS)
143 /* XXX to do */
144 driverName = _weglChooseDriver(dpy);
145 #elif defined(_EGL_PLATFORM_WINCE)
146 /* XXX to do */
147 #else
148 driverName = DefaultDriverName;
149 #endif
150 }
151
152 return driverName;
153 }
154
155
156 /**
157 * Open/load the named driver and call its bootstrap function: _eglMain().
158 * By the time this function is called, the dpy->DriverName should have
159 * been determined.
160 *
161 * \return new _EGLDriver object.
162 */
163 _EGLDriver *
164 _eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args)
165 {
166 _EGLDriver *drv;
167 _EGLMain_t mainFunc;
168 #if defined(_EGL_PLATFORM_WINDOWS)
169 HMODULE lib;
170 #elif defined(_EGL_PLATFORM_X)
171 void *lib;
172 #endif
173 char driverFilename[1000];
174
175 assert(driverName);
176
177 #if defined(_EGL_PLATFORM_WINDOWS)
178 /* XXX untested */
179 sprintf(driverFilename, "%s.dll", driverName);
180 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
181 lib = LoadLibrary(driverFilename);
182 #elif defined(_EGL_PLATFORM_X)
183 /* XXX also prepend a directory path??? */
184 sprintf(driverFilename, "%s.so", driverName);
185 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
186 lib = dlopen(driverFilename, RTLD_LAZY);
187 #endif
188
189 if (!lib) {
190 _eglLog(_EGL_WARNING, "Could not open %s (%s)",
191 driverFilename, dlerror());
192 return NULL;
193 }
194
195 #if defined(_EGL_PLATFORM_WINDOWS)
196 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
197 #elif defined(_EGL_PLATFORM_X)
198 mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
199 #endif
200
201 if (!mainFunc) {
202 _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename);
203 #if defined(_EGL_PLATFORM_WINDOWS)
204 FreeLibrary(lib);
205 #elif defined(_EGL_PLATFORM_X)
206 dlclose(lib);
207 #endif
208 return NULL;
209 }
210
211 drv = mainFunc(dpy, args);
212 if (!drv) {
213 #if defined(_EGL_PLATFORM_WINDOWS)
214 FreeLibrary(lib);
215 #elif defined(_EGL_PLATFORM_X)
216 dlclose(lib);
217 #endif
218 return NULL;
219 }
220
221 /* with a recurvise open you want the inner most handle */
222 if (!drv->LibHandle) {
223 drv->LibHandle = lib;
224 }
225 else {
226 #if defined(_EGL_PLATFORM_WINDOWS)
227 FreeLibrary(lib);
228 #elif defined(_EGL_PLATFORM_X)
229 dlclose(lib);
230 #endif
231 }
232
233 /* update the global notion of supported APIs */
234 _eglGlobal.ClientAPIsMask |= drv->ClientAPIsMask;
235
236 _eglSaveDriver(drv);
237
238 return drv;
239 }
240
241
242 EGLBoolean
243 _eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy)
244 {
245 void *handle = drv->LibHandle;
246 EGLBoolean b;
247
248 _eglLog(_EGL_DEBUG, "Closing %s", drv->Name);
249
250 /*
251 * XXX check for currently bound context/surfaces and delete them?
252 */
253
254 b = drv->API.Terminate(drv, dpy);
255
256 #if defined(_EGL_PLATFORM_WINDOWS)
257 FreeLibrary(handle);
258 #elif defined(_EGL_PLATFORM_X)
259 dlclose(handle);
260 #endif
261
262 return b;
263 }
264
265
266 /**
267 * Save the given driver pointer in the list of all known drivers.
268 */
269 void
270 _eglSaveDriver(_EGLDriver *drv)
271 {
272 _eglGlobal.Drivers[ _eglGlobal.NumDrivers++ ] = drv;
273 }
274
275
276 /**
277 * Given a display handle, return the _EGLDriver for that display.
278 */
279 _EGLDriver *
280 _eglLookupDriver(EGLDisplay dpy)
281 {
282 _EGLDisplay *d = _eglLookupDisplay(dpy);
283 if (d)
284 return d->Driver;
285 else
286 return NULL;
287 }
288
289
290 /**
291 * Plug all the available fallback routines into the given driver's
292 * dispatch table.
293 */
294 void
295 _eglInitDriverFallbacks(_EGLDriver *drv)
296 {
297 /* If a pointer is set to NULL, then the device driver _really_ has
298 * to implement it.
299 */
300 drv->API.Initialize = NULL;
301 drv->API.Terminate = NULL;
302
303 drv->API.GetConfigs = _eglGetConfigs;
304 drv->API.ChooseConfig = _eglChooseConfig;
305 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
306
307 drv->API.CreateContext = _eglCreateContext;
308 drv->API.DestroyContext = _eglDestroyContext;
309 drv->API.MakeCurrent = _eglMakeCurrent;
310 drv->API.QueryContext = _eglQueryContext;
311
312 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
313 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
314 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
315 drv->API.DestroySurface = _eglDestroySurface;
316 drv->API.QuerySurface = _eglQuerySurface;
317 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
318 drv->API.BindTexImage = _eglBindTexImage;
319 drv->API.ReleaseTexImage = _eglReleaseTexImage;
320 drv->API.SwapInterval = _eglSwapInterval;
321 drv->API.SwapBuffers = _eglSwapBuffers;
322 drv->API.CopyBuffers = _eglCopyBuffers;
323
324 drv->API.QueryString = _eglQueryString;
325 drv->API.WaitGL = _eglWaitGL;
326 drv->API.WaitNative = _eglWaitNative;
327
328 #ifdef EGL_MESA_screen_surface
329 drv->API.ChooseModeMESA = _eglChooseModeMESA;
330 drv->API.GetModesMESA = _eglGetModesMESA;
331 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
332 drv->API.GetScreensMESA = _eglGetScreensMESA;
333 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
334 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
335 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
336 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
337 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
338 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
339 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
340 #endif /* EGL_MESA_screen_surface */
341
342 #ifdef EGL_VERSION_1_2
343 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
344 #endif /* EGL_VERSION_1_2 */
345 }