egl: remove unnecessary empty array element
[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 };
67
68 /**
69 * Load a module and create the driver object.
70 */
71 static EGLBoolean
72 _eglLoadModule(_EGLModule *mod)
73 {
74 _EGLDriver *drv;
75
76 if (mod->Driver)
77 return EGL_TRUE;
78
79 if (!mod->BuiltIn)
80 return EGL_FALSE;
81
82 drv = mod->BuiltIn(NULL);
83 if (!drv || !drv->Name)
84 return EGL_FALSE;
85
86 mod->Driver = drv;
87
88 return EGL_TRUE;
89 }
90
91
92 /**
93 * Unload a module.
94 */
95 static void
96 _eglUnloadModule(_EGLModule *mod)
97 {
98 /* destroy the driver */
99 if (mod->Driver && mod->Driver->Unload)
100 mod->Driver->Unload(mod->Driver);
101
102 mod->Driver = NULL;
103 }
104
105
106 /**
107 * Add a module to the module array.
108 */
109 static _EGLModule *
110 _eglAddModule(const char *name)
111 {
112 _EGLModule *mod;
113 EGLint i;
114
115 if (!_eglModules) {
116 _eglModules = _eglCreateArray("Module", 8);
117 if (!_eglModules)
118 return NULL;
119 }
120
121 /* find duplicates */
122 for (i = 0; i < _eglModules->Size; i++) {
123 mod = _eglModules->Elements[i];
124 if (strcmp(mod->Name, name) == 0)
125 return mod;
126 }
127
128 /* allocate a new one */
129 mod = calloc(1, sizeof(*mod));
130 if (mod) {
131 mod->Name = strdup(name);
132 if (!mod->Name) {
133 free(mod);
134 mod = NULL;
135 }
136 }
137 if (mod) {
138 _eglAppendArray(_eglModules, (void *) mod);
139 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Name);
140 }
141
142 return mod;
143 }
144
145
146 /**
147 * Free a module.
148 */
149 static void
150 _eglFreeModule(void *module)
151 {
152 _EGLModule *mod = (_EGLModule *) module;
153
154 _eglUnloadModule(mod);
155 free(mod->Name);
156 free(mod);
157 }
158
159
160 /**
161 * Add the user driver to the module array.
162 *
163 * The user driver is specified by EGL_DRIVER.
164 */
165 static EGLBoolean
166 _eglAddUserDriver(void)
167 {
168 char *env;
169
170 env = getenv("EGL_DRIVER");
171 if (env) {
172 EGLint i;
173
174 for (i = 0; i < ARRAY_SIZE(_eglBuiltInDrivers); i++) {
175 if (!strcmp(_eglBuiltInDrivers[i].name, env)) {
176 _EGLModule *mod = _eglAddModule(env);
177 if (mod)
178 mod->BuiltIn = _eglBuiltInDrivers[i].main;
179
180 return EGL_TRUE;
181 }
182 }
183 }
184
185 return EGL_FALSE;
186 }
187
188
189 /**
190 * Add built-in drivers to the module array.
191 */
192 static void
193 _eglAddBuiltInDrivers(void)
194 {
195 _EGLModule *mod;
196 EGLint i;
197
198 for (i = 0; i < ARRAY_SIZE(_eglBuiltInDrivers); i++) {
199 mod = _eglAddModule(_eglBuiltInDrivers[i].name);
200 if (mod)
201 mod->BuiltIn = _eglBuiltInDrivers[i].main;
202 }
203 }
204
205
206 /**
207 * Add drivers to the module array. Drivers will be loaded as they are matched
208 * to displays.
209 */
210 static EGLBoolean
211 _eglAddDrivers(void)
212 {
213 if (_eglModules)
214 return EGL_TRUE;
215
216 if (!_eglAddUserDriver()) {
217 /*
218 * Add other drivers only when EGL_DRIVER is not set. The order here
219 * decides the priorities.
220 */
221 _eglAddBuiltInDrivers();
222 }
223
224 return (_eglModules != NULL);
225 }
226
227
228 /**
229 * A helper function for _eglMatchDriver. It finds the first driver that can
230 * initialize the display and return.
231 */
232 static _EGLDriver *
233 _eglMatchAndInitialize(_EGLDisplay *dpy)
234 {
235 _EGLDriver *drv = NULL;
236 EGLint i = 0;
237
238 if (!_eglAddDrivers()) {
239 _eglLog(_EGL_WARNING, "failed to find any driver");
240 return NULL;
241 }
242
243 if (dpy->Driver) {
244 drv = dpy->Driver;
245 /* no re-matching? */
246 if (!drv->API.Initialize(drv, dpy))
247 drv = NULL;
248 return drv;
249 }
250
251 while (i < _eglModules->Size) {
252 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
253
254 if (!_eglLoadModule(mod)) {
255 /* remove invalid modules */
256 _eglEraseArray(_eglModules, i, _eglFreeModule);
257 continue;
258 }
259
260 if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
261 drv = mod->Driver;
262 break;
263 }
264 else {
265 i++;
266 }
267 }
268
269 return drv;
270 }
271
272
273 /**
274 * Match a display to a driver. The display is initialized unless test_only is
275 * true. The matching is done by finding the first driver that can initialize
276 * the display.
277 */
278 _EGLDriver *
279 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
280 {
281 _EGLDriver *best_drv;
282
283 assert(!dpy->Initialized);
284
285 mtx_lock(&_eglModuleMutex);
286
287 /* set options */
288 dpy->Options.TestOnly = test_only;
289 dpy->Options.UseFallback = EGL_FALSE;
290
291 best_drv = _eglMatchAndInitialize(dpy);
292 if (!best_drv) {
293 dpy->Options.UseFallback = EGL_TRUE;
294 best_drv = _eglMatchAndInitialize(dpy);
295 }
296
297 mtx_unlock(&_eglModuleMutex);
298
299 if (best_drv) {
300 _eglLog(_EGL_DEBUG, "the best driver is %s%s",
301 best_drv->Name, (test_only) ? " (test only) " : "");
302 if (!test_only) {
303 dpy->Driver = best_drv;
304 dpy->Initialized = EGL_TRUE;
305 }
306 }
307
308 return best_drv;
309 }
310
311
312 __eglMustCastToProperFunctionPointerType
313 _eglGetDriverProc(const char *procname)
314 {
315 EGLint i;
316 _EGLProc proc = NULL;
317
318 if (!_eglModules) {
319 /* load the driver for the default display */
320 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
321 _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
322 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
323 return NULL;
324 }
325
326 for (i = 0; i < _eglModules->Size; i++) {
327 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
328
329 if (!mod->Driver)
330 break;
331 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
332 if (proc)
333 break;
334 }
335
336 return proc;
337 }
338
339
340 /**
341 * Unload all drivers.
342 */
343 void
344 _eglUnloadDrivers(void)
345 {
346 /* this is called at atexit time */
347 if (_eglModules) {
348 _eglDestroyArray(_eglModules, _eglFreeModule);
349 _eglModules = NULL;
350 }
351 }