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