Home | History | Annotate | Download | only in main
      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