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