egl: remove custom string functions
[mesa.git] / src / egl / main / egldriver.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31 /**
32 * Functions for choosing and opening/loading device drivers.
33 */
34
35
36 #include <assert.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include "c11/threads.h"
41
42 #include "egldefines.h"
43 #include "egldisplay.h"
44 #include "egldriver.h"
45 #include "egllog.h"
46
47 typedef struct _egl_module {
48 char *Name;
49 _EGLMain_t BuiltIn;
50 _EGLDriver *Driver;
51 } _EGLModule;
52
53 static mtx_t _eglModuleMutex = _MTX_INITIALIZER_NP;
54 static _EGLArray *_eglModules;
55
56 const struct {
57 const char *name;
58 _EGLMain_t main;
59 } _eglBuiltInDrivers[] = {
60 #ifdef _EGL_BUILT_IN_DRIVER_DRI2
61 { "egl_dri2", _eglBuiltInDriverDRI2 },
62 #endif
63 #ifdef _EGL_BUILT_IN_DRIVER_HAIKU
64 { "egl_haiku", _eglBuiltInDriverHaiku },
65 #endif
66 { NULL, NULL }
67 };
68
69 /**
70 * Load a module and create the driver object.
71 */
72 static EGLBoolean
73 _eglLoadModule(_EGLModule *mod)
74 {
75 _EGLDriver *drv;
76
77 if (mod->Driver)
78 return EGL_TRUE;
79
80 if (!mod->BuiltIn)
81 return EGL_FALSE;
82
83 drv = mod->BuiltIn(NULL);
84 if (!drv || !drv->Name)
85 return EGL_FALSE;
86
87 mod->Driver = drv;
88
89 return EGL_TRUE;
90 }
91
92
93 /**
94 * Unload a module.
95 */
96 static void
97 _eglUnloadModule(_EGLModule *mod)
98 {
99 #if defined(_EGL_OS_UNIX)
100 /* destroy the driver */
101 if (mod->Driver && mod->Driver->Unload)
102 mod->Driver->Unload(mod->Driver);
103
104 #elif defined(_EGL_OS_WINDOWS)
105 /* XXX Windows unloads DLLs before atexit */
106 #endif
107
108 mod->Driver = NULL;
109 }
110
111
112 /**
113 * Add a module to the module array.
114 */
115 static _EGLModule *
116 _eglAddModule(const char *name)
117 {
118 _EGLModule *mod;
119 EGLint i;
120
121 if (!_eglModules) {
122 _eglModules = _eglCreateArray("Module", 8);
123 if (!_eglModules)
124 return NULL;
125 }
126
127 /* find duplicates */
128 for (i = 0; i < _eglModules->Size; i++) {
129 mod = _eglModules->Elements[i];
130 if (strcmp(mod->Name, name) == 0)
131 return mod;
132 }
133
134 /* allocate a new one */
135 mod = calloc(1, sizeof(*mod));
136 if (mod) {
137 mod->Name = strdup(name);
138 if (!mod->Name) {
139 free(mod);
140 mod = NULL;
141 }
142 }
143 if (mod) {
144 _eglAppendArray(_eglModules, (void *) mod);
145 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Name);
146 }
147
148 return mod;
149 }
150
151
152 /**
153 * Free a module.
154 */
155 static void
156 _eglFreeModule(void *module)
157 {
158 _EGLModule *mod = (_EGLModule *) module;
159
160 _eglUnloadModule(mod);
161 free(mod->Name);
162 free(mod);
163 }
164
165
166 /**
167 * Add the user driver to the module array.
168 *
169 * The user driver is specified by EGL_DRIVER.
170 */
171 static EGLBoolean
172 _eglAddUserDriver(void)
173 {
174 char *env;
175
176 env = getenv("EGL_DRIVER");
177 if (env) {
178 EGLint i;
179
180 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
181 if (!strcmp(_eglBuiltInDrivers[i].name, env)) {
182 _EGLModule *mod = _eglAddModule(env);
183 if (mod)
184 mod->BuiltIn = _eglBuiltInDrivers[i].main;
185
186 return EGL_TRUE;
187 }
188 }
189 }
190
191 return EGL_FALSE;
192 }
193
194
195 /**
196 * Add built-in drivers to the module array.
197 */
198 static void
199 _eglAddBuiltInDrivers(void)
200 {
201 _EGLModule *mod;
202 EGLint i;
203
204 for (i = 0; _eglBuiltInDrivers[i].name; i++) {
205 mod = _eglAddModule(_eglBuiltInDrivers[i].name);
206 if (mod)
207 mod->BuiltIn = _eglBuiltInDrivers[i].main;
208 }
209 }
210
211
212 /**
213 * Add drivers to the module array. Drivers will be loaded as they are matched
214 * to displays.
215 */
216 static EGLBoolean
217 _eglAddDrivers(void)
218 {
219 if (_eglModules)
220 return EGL_TRUE;
221
222 if (!_eglAddUserDriver()) {
223 /*
224 * Add other drivers only when EGL_DRIVER is not set. The order here
225 * decides the priorities.
226 */
227 _eglAddBuiltInDrivers();
228 }
229
230 return (_eglModules != NULL);
231 }
232
233
234 /**
235 * A helper function for _eglMatchDriver. It finds the first driver that can
236 * initialize the display and return.
237 */
238 static _EGLDriver *
239 _eglMatchAndInitialize(_EGLDisplay *dpy)
240 {
241 _EGLDriver *drv = NULL;
242 EGLint i = 0;
243
244 if (!_eglAddDrivers()) {
245 _eglLog(_EGL_WARNING, "failed to find any driver");
246 return NULL;
247 }
248
249 if (dpy->Driver) {
250 drv = dpy->Driver;
251 /* no re-matching? */
252 if (!drv->API.Initialize(drv, dpy))
253 drv = NULL;
254 return drv;
255 }
256
257 while (i < _eglModules->Size) {
258 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
259
260 if (!_eglLoadModule(mod)) {
261 /* remove invalid modules */
262 _eglEraseArray(_eglModules, i, _eglFreeModule);
263 continue;
264 }
265
266 if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
267 drv = mod->Driver;
268 break;
269 }
270 else {
271 i++;
272 }
273 }
274
275 return drv;
276 }
277
278
279 /**
280 * Match a display to a driver. The display is initialized unless test_only is
281 * true. The matching is done by finding the first driver that can initialize
282 * the display.
283 */
284 _EGLDriver *
285 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
286 {
287 _EGLDriver *best_drv;
288
289 assert(!dpy->Initialized);
290
291 mtx_lock(&_eglModuleMutex);
292
293 /* set options */
294 dpy->Options.TestOnly = test_only;
295 dpy->Options.UseFallback = EGL_FALSE;
296
297 best_drv = _eglMatchAndInitialize(dpy);
298 if (!best_drv) {
299 dpy->Options.UseFallback = EGL_TRUE;
300 best_drv = _eglMatchAndInitialize(dpy);
301 }
302
303 mtx_unlock(&_eglModuleMutex);
304
305 if (best_drv) {
306 _eglLog(_EGL_DEBUG, "the best driver is %s%s",
307 best_drv->Name, (test_only) ? " (test only) " : "");
308 if (!test_only) {
309 dpy->Driver = best_drv;
310 dpy->Initialized = EGL_TRUE;
311 }
312 }
313
314 return best_drv;
315 }
316
317
318 __eglMustCastToProperFunctionPointerType
319 _eglGetDriverProc(const char *procname)
320 {
321 EGLint i;
322 _EGLProc proc = NULL;
323
324 if (!_eglModules) {
325 /* load the driver for the default display */
326 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
327 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
328 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
329 return NULL;
330 }
331
332 for (i = 0; i < _eglModules->Size; i++) {
333 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
334
335 if (!mod->Driver)
336 break;
337 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
338 if (proc)
339 break;
340 }
341
342 return proc;
343 }
344
345
346 /**
347 * Unload all drivers.
348 */
349 void
350 _eglUnloadDrivers(void)
351 {
352 /* this is called at atexit time */
353 if (_eglModules) {
354 _eglDestroyArray(_eglModules, _eglFreeModule);
355 _eglModules = NULL;
356 }
357 }