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