egl: check for EGL_DRIVER env var to override normal driver selection process
[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 <dlfcn.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "eglconfig.h"
12 #include "eglcontext.h"
13 #include "egldefines.h"
14 #include "egldisplay.h"
15 #include "egldriver.h"
16 #include "eglglobals.h"
17 #include "egllog.h"
18 #include "eglmisc.h"
19 #include "eglmode.h"
20 #include "eglscreen.h"
21 #include "eglstring.h"
22 #include "eglsurface.h"
23
24 #if defined(_EGL_PLATFORM_X)
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 const char *DefaultDriverName = ":0";
34 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 static 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 * Determine/return the name of the driver to use for the given _EGLDisplay.
76 *
77 * Try to be clever and determine if nativeDisplay is an Xlib Display
78 * ptr or a string (naming a driver or screen number, etc).
79 *
80 * If the first character is ':' we interpret it as a screen or card index
81 * number (i.e. ":0" or ":1", etc)
82 * Else if the first character is '!' we interpret it as specific driver name
83 * (i.e. "!r200" or "!i830".
84 *
85 * Whatever follows ':' is copied and put into dpy->DriverArgs.
86 *
87 * The caller may free() the returned string.
88 */
89 const char *
90 _eglChooseDriver(_EGLDisplay *dpy)
91 {
92 const char *displayString = (const char *) dpy->NativeDisplay;
93 const char *driverName = NULL;
94
95 /* First, if the EGL_DRIVER env var is set, use that */
96 driverName = getenv("EGL_DRIVER");
97 if (driverName)
98 return _eglstrdup(driverName);
99
100
101 if (!displayString) {
102 /* choose a default */
103 displayString = DefaultDriverName;
104 }
105
106 /* extract default DriverArgs = whatever follows ':' */
107 if (displayString &&
108 (displayString[0] == '!' ||
109 displayString[0] == ':')) {
110 const char *args = strchr(displayString, ':');
111 if (args)
112 dpy->DriverArgs = _eglstrdup(args + 1);
113 }
114
115 /* determine driver name now */
116 if (displayString && displayString[0] == ':' &&
117 (displayString[1] >= '0' && displayString[1] <= '9') &&
118 !displayString[2]) {
119 int card = atoi(displayString + 1);
120 driverName = _eglChooseDRMDriver(card);
121 }
122 else if (displayString && displayString[0] == '!') {
123 /* use user-specified driver name */
124 driverName = _eglstrdup(displayString + 1);
125 /* truncate driverName at ':' if present */
126 {
127 char *args = strchr(driverName, ':');
128 if (args) {
129 *args = 0;
130 }
131 }
132 }
133 else {
134 /* NativeDisplay is not a string! */
135 #if defined(_EGL_PLATFORM_X)
136 driverName = _xeglChooseDriver(dpy);
137 #elif defined(_EGL_PLATFORM_WINDOWS)
138 /* XXX to do */
139 driverName = _weglChooseDriver(dpy);
140 #elif defined(_EGL_PLATFORM_WINCE)
141 /* XXX to do */
142 #endif
143 }
144
145 return driverName;
146 }
147
148
149 /**
150 * Open/load the named driver and call its bootstrap function: _eglMain().
151 * By the time this function is called, the dpy->DriverName should have
152 * been determined.
153 *
154 * \return new _EGLDriver object.
155 */
156 _EGLDriver *
157 _eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args)
158 {
159 _EGLDriver *drv;
160 _EGLMain_t mainFunc;
161 void *lib;
162 char driverFilename[1000];
163
164 assert(driverName);
165
166 /* XXX also prepend a directory path??? */
167 sprintf(driverFilename, "%s.so", driverName);
168
169 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
170 lib = dlopen(driverFilename, RTLD_NOW);
171 if (!lib) {
172 _eglLog(_EGL_WARNING, "Could not open %s (%s)",
173 driverFilename, dlerror());
174 return NULL;
175 }
176
177 mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
178 if (!mainFunc) {
179 _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename);
180 dlclose(lib);
181 return NULL;
182 }
183
184 drv = mainFunc(dpy, args);
185 if (!drv) {
186 dlclose(lib);
187 return NULL;
188 }
189 /* with a recurvise open you want the inner most handle */
190 if (!drv->LibHandle)
191 drv->LibHandle = lib;
192 else
193 dlclose(lib);
194
195 return drv;
196 }
197
198
199 EGLBoolean
200 _eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy)
201 {
202 void *handle = drv->LibHandle;
203 EGLBoolean b;
204
205 _eglLog(_EGL_INFO, "Closing driver");
206
207 /*
208 * XXX check for currently bound context/surfaces and delete them?
209 */
210
211 b = drv->API.Terminate(drv, dpy);
212 dlclose(handle);
213 return b;
214 }
215
216
217 /**
218 * Given a display handle, return the _EGLDriver for that display.
219 */
220 _EGLDriver *
221 _eglLookupDriver(EGLDisplay dpy)
222 {
223 _EGLDisplay *d = _eglLookupDisplay(dpy);
224 if (d)
225 return d->Driver;
226 else
227 return NULL;
228 }
229
230
231 /**
232 * Plug all the available fallback routines into the given driver's
233 * dispatch table.
234 */
235 void
236 _eglInitDriverFallbacks(_EGLDriver *drv)
237 {
238 /* If a pointer is set to NULL, then the device driver _really_ has
239 * to implement it.
240 */
241 drv->API.Initialize = NULL;
242 drv->API.Terminate = NULL;
243
244 drv->API.GetConfigs = _eglGetConfigs;
245 drv->API.ChooseConfig = _eglChooseConfig;
246 drv->API.GetConfigAttrib = _eglGetConfigAttrib;
247
248 drv->API.CreateContext = _eglCreateContext;
249 drv->API.DestroyContext = _eglDestroyContext;
250 drv->API.MakeCurrent = _eglMakeCurrent;
251 drv->API.QueryContext = _eglQueryContext;
252
253 drv->API.CreateWindowSurface = _eglCreateWindowSurface;
254 drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
255 drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
256 drv->API.DestroySurface = _eglDestroySurface;
257 drv->API.QuerySurface = _eglQuerySurface;
258 drv->API.SurfaceAttrib = _eglSurfaceAttrib;
259 drv->API.BindTexImage = _eglBindTexImage;
260 drv->API.ReleaseTexImage = _eglReleaseTexImage;
261 drv->API.SwapInterval = _eglSwapInterval;
262 drv->API.SwapBuffers = _eglSwapBuffers;
263 drv->API.CopyBuffers = _eglCopyBuffers;
264
265 drv->API.QueryString = _eglQueryString;
266 drv->API.WaitGL = _eglWaitGL;
267 drv->API.WaitNative = _eglWaitNative;
268
269 #ifdef EGL_MESA_screen_surface
270 drv->API.ChooseModeMESA = _eglChooseModeMESA;
271 drv->API.GetModesMESA = _eglGetModesMESA;
272 drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
273 drv->API.GetScreensMESA = _eglGetScreensMESA;
274 drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
275 drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
276 drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
277 drv->API.QueryScreenMESA = _eglQueryScreenMESA;
278 drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
279 drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
280 drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
281 #endif /* EGL_MESA_screen_surface */
282
283 #ifdef EGL_VERSION_1_2
284 drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
285 #endif /* EGL_VERSION_1_2 */
286 }