Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
  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.  
  41. #include "eglstring.h"
  42. #include "egldefines.h"
  43. #include "egldisplay.h"
  44. #include "egldriver.h"
  45. #include "egllog.h"
  46. #include "eglmutex.h"
  47.  
  48. typedef unsigned int lib_handle;
  49.  
  50. lib_handle load_library(const char *name);
  51. void *get_proc_address(lib_handle lib, char *proc_name);
  52.  
  53.  
  54. typedef struct _egl_module {
  55.    char *Path;
  56.    _EGLMain_t BuiltIn;
  57.    void *Handle;
  58.    _EGLDriver *Driver;
  59. } _EGLModule;
  60.  
  61. static _EGL_DECLARE_MUTEX(_eglModuleMutex);
  62. static _EGLArray *_eglModules;
  63.  
  64. const struct {
  65.    const char *name;
  66.    _EGLMain_t main;
  67. } _eglBuiltInDrivers[] = {
  68. #ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
  69.    { "egl_gallium", _eglBuiltInDriverGALLIUM },
  70. #endif
  71. #ifdef _EGL_BUILT_IN_DRIVER_DRI2
  72.    { "egl_dri2", _eglBuiltInDriverDRI2 },
  73. #endif
  74. #ifdef _EGL_BUILT_IN_DRIVER_GLX
  75.    { "egl_glx", _eglBuiltInDriverGLX },
  76. #endif
  77.    { NULL, NULL }
  78. };
  79.  
  80. /**
  81.  * Wrappers for dlopen/dlclose()
  82.  */
  83. #if defined(_EGL_OS_WINDOWS)
  84.  
  85.  
  86. typedef HMODULE lib_handle;
  87.  
  88. static HMODULE
  89. open_library(const char *filename)
  90. {
  91.    return LoadLibrary(filename);
  92. }
  93.  
  94. static void
  95. close_library(HMODULE lib)
  96. {
  97.    FreeLibrary(lib);
  98. }
  99.  
  100.  
  101. static const char *
  102. library_suffix(void)
  103. {
  104.    return ".dll";
  105. }
  106.  
  107.  
  108. #elif defined(_EGL_OS_UNIX)
  109.  
  110.  
  111. typedef void * lib_handle;
  112.  
  113. static void *
  114. open_library(const char *filename)
  115. {
  116.    return dlopen(filename, RTLD_LAZY);
  117. }
  118.  
  119. static void
  120. close_library(void *lib)
  121. {
  122.    dlclose(lib);
  123. }
  124.  
  125.  
  126. static const char *
  127. library_suffix(void)
  128. {
  129.    return ".so";
  130. }
  131.  
  132.  
  133. #endif
  134.  
  135. /**
  136.  * Open the named driver and find its bootstrap function: _eglMain().
  137.  */
  138. static _EGLMain_t
  139. _eglOpenLibrary(const char *driverPath, lib_handle *handle)
  140. {
  141.    lib_handle lib;
  142.    _EGLMain_t mainFunc = NULL;
  143.    const char *error = "unknown error";
  144.  
  145.    assert(driverPath);
  146.  
  147.    _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
  148.    lib = load_library(driverPath);
  149.    if (!lib) {
  150.       _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
  151.               driverPath, error);
  152.       return NULL;
  153.    }
  154.  
  155.    mainFunc = (_EGLMain_t) get_proc_address(lib, "_eglMain");
  156.  
  157.    if (!mainFunc) {
  158.       _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
  159.               driverPath, error);
  160.       return NULL;
  161.    }
  162.  
  163.    *handle = lib;
  164.    return mainFunc;
  165. }
  166.  
  167.  
  168. /**
  169.  * Load a module and create the driver object.
  170.  */
  171. static EGLBoolean
  172. _eglLoadModule(_EGLModule *mod)
  173. {
  174.    _EGLMain_t mainFunc;
  175.    lib_handle lib;
  176.    _EGLDriver *drv;
  177.  
  178.    if (mod->Driver)
  179.       return EGL_TRUE;
  180.  
  181.    if (mod->BuiltIn) {
  182.       lib = (lib_handle) NULL;
  183.       mainFunc = mod->BuiltIn;
  184.    }
  185.    else {
  186.       mainFunc = _eglOpenLibrary(mod->Path, &lib);
  187.       if (!mainFunc)
  188.          return EGL_FALSE;
  189.    }
  190.  
  191.    drv = mainFunc(NULL);
  192.    if (!drv) {
  193.       return EGL_FALSE;
  194.    }
  195.  
  196.    if (!drv->Name) {
  197.       _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
  198.       drv->Name = "UNNAMED";
  199.    }
  200.  
  201.    mod->Handle = (void *) lib;
  202.    mod->Driver = drv;
  203.  
  204.    return EGL_TRUE;
  205. }
  206.  
  207.  
  208. /**
  209.  * Unload a module.
  210.  */
  211. static void
  212. _eglUnloadModule(_EGLModule *mod)
  213. {
  214. #if defined(_EGL_OS_UNIX)
  215.    /* destroy the driver */
  216.    if (mod->Driver && mod->Driver->Unload)
  217.       mod->Driver->Unload(mod->Driver);
  218.  
  219.    /*
  220.     * XXX At this point (atexit), the module might be the last reference to
  221.     * libEGL.  Closing the module might unmap libEGL and give problems.
  222.     */
  223. #if 0
  224.    if (mod->Handle)
  225.       close_library(mod->Handle);
  226. #endif
  227. #elif defined(_EGL_OS_WINDOWS)
  228.    /* XXX Windows unloads DLLs before atexit */
  229. #endif
  230.  
  231.    mod->Driver = NULL;
  232.    mod->Handle = NULL;
  233. }
  234.  
  235.  
  236. /**
  237.  * Add a module to the module array.
  238.  */
  239. static _EGLModule *
  240. _eglAddModule(const char *path)
  241. {
  242.    _EGLModule *mod;
  243.    EGLint i;
  244.  
  245.    if (!_eglModules) {
  246.       _eglModules = _eglCreateArray("Module", 8);
  247.       if (!_eglModules)
  248.          return NULL;
  249.    }
  250.  
  251.    /* find duplicates */
  252.    for (i = 0; i < _eglModules->Size; i++) {
  253.       mod = _eglModules->Elements[i];
  254.       if (strcmp(mod->Path, path) == 0)
  255.          return mod;
  256.    }
  257.  
  258.    /* allocate a new one */
  259.    mod = calloc(1, sizeof(*mod));
  260.    if (mod) {
  261.       mod->Path = _eglstrdup(path);
  262.       if (!mod->Path) {
  263.          free(mod);
  264.          mod = NULL;
  265.       }
  266.    }
  267.    if (mod) {
  268.       _eglAppendArray(_eglModules, (void *) mod);
  269.       _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
  270.    }
  271.  
  272.    return mod;
  273. }
  274.  
  275.  
  276. /**
  277.  * Free a module.
  278.  */
  279. static void
  280. _eglFreeModule(void *module)
  281. {
  282.    _EGLModule *mod = (_EGLModule *) module;
  283.  
  284.    _eglUnloadModule(mod);
  285.    free(mod->Path);
  286.    free(mod);
  287. }
  288.  
  289. #if 0
  290. /**
  291.  * A loader function for use with _eglPreloadForEach.  The loader data is the
  292.  * filename of the driver.   This function stops on the first valid driver.
  293.  */
  294. static EGLBoolean
  295. _eglLoaderFile(const char *dir, size_t len, void *loader_data)
  296. {
  297.    char path[1024];
  298.    const char *filename = (const char *) loader_data;
  299.    size_t flen = strlen(filename);
  300.  
  301.    /* make a full path */
  302.    if (len + flen + 2 > sizeof(path))
  303.       return EGL_TRUE;
  304.    if (len) {
  305.       memcpy(path, dir, len);
  306.       path[len++] = '/';
  307.    }
  308.    memcpy(path + len, filename, flen);
  309.    len += flen;
  310.    path[len] = '\0';
  311.  
  312.    if (library_suffix()) {
  313.       const char *suffix = library_suffix();
  314.       size_t slen = strlen(suffix);
  315.       const char *p;
  316.       EGLBoolean need_suffix;
  317.  
  318.       p = filename + flen - slen;
  319.       need_suffix = (p < filename || strcmp(p, suffix) != 0);
  320.       if (need_suffix) {
  321.          /* overflow */
  322.          if (len + slen + 1 > sizeof(path))
  323.             return EGL_TRUE;
  324.          strcpy(path + len, suffix);
  325.       }
  326.    }
  327.  
  328. #if defined(_EGL_OS_UNIX)
  329.    /* check if the file exists */
  330.    if (access(path, F_OK))
  331.       return EGL_TRUE;
  332. #endif
  333.  
  334.    _eglAddModule(path);
  335.  
  336.    return EGL_TRUE;
  337. }
  338.  
  339.  
  340. /**
  341.  * Run the callback function on each driver directory.
  342.  *
  343.  * The process may end prematurely if the callback function returns false.
  344.  */
  345. static void
  346. _eglPreloadForEach(const char *search_path,
  347.                    EGLBoolean (*loader)(const char *, size_t, void *),
  348.                    void *loader_data)
  349. {
  350.    const char *cur, *next;
  351.    size_t len;
  352.  
  353.    cur = search_path;
  354.    while (cur) {
  355.       next = strchr(cur, ':');
  356.       len = (next) ? next - cur : strlen(cur);
  357.  
  358.       if (!loader(cur, len, loader_data))
  359.          break;
  360.  
  361.       cur = (next) ? next + 1 : NULL;
  362.    }
  363. }
  364.  
  365.  
  366. /**
  367.  * Return a list of colon-separated driver directories.
  368.  */
  369. static const char *
  370. _eglGetSearchPath(void)
  371. {
  372.    static char search_path[1024];
  373.  
  374. #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
  375.    if (search_path[0] == '\0') {
  376.       char *buf = search_path;
  377.       size_t len = sizeof(search_path);
  378.       EGLBoolean use_env;
  379.       char dir_sep;
  380.       int ret;
  381.  
  382. #if defined(_EGL_OS_UNIX)
  383.       use_env = (geteuid() == getuid() && getegid() == getgid());
  384.       dir_sep = '/';
  385. #else
  386.       use_env = EGL_TRUE;
  387.       dir_sep = '\\';
  388. #endif
  389.  
  390.       if (use_env) {
  391.          char *p;
  392.  
  393.          /* extract the dirname from EGL_DRIVER */
  394.          p = getenv("EGL_DRIVER");
  395.          if (p && strchr(p, dir_sep)) {
  396.             ret = _eglsnprintf(buf, len, "%s", p);
  397.             if (ret > 0 && ret < len) {
  398.                p = strrchr(buf, dir_sep);
  399.                *p++ = ':';
  400.  
  401.                len -= p - buf;
  402.                buf = p;
  403.             }
  404.          }
  405.  
  406.          /* append EGL_DRIVERS_PATH */
  407.          p = getenv("EGL_DRIVERS_PATH");
  408.          if (p) {
  409.             ret = _eglsnprintf(buf, len, "%s:", p);
  410.             if (ret > 0 && ret < len) {
  411.                buf += ret;
  412.                len -= ret;
  413.             }
  414.          }
  415.       }
  416.       else {
  417.          _eglLog(_EGL_DEBUG,
  418.                "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
  419.       }
  420.  
  421.       ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR);
  422.       if (ret < 0 || ret >= len)
  423.          search_path[0] = '\0';
  424.  
  425.       _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path);
  426.    }
  427. #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
  428.  
  429.    return search_path;
  430. }
  431.  
  432.  
  433. /**
  434.  * Add the user driver to the module array.
  435.  *
  436.  * The user driver is specified by EGL_DRIVER.
  437.  */
  438. static EGLBoolean
  439. _eglAddUserDriver(void)
  440. {
  441.    const char *search_path = _eglGetSearchPath();
  442.    char *env;
  443.    size_t name_len = 0;
  444.  
  445.    env = getenv("EGL_DRIVER");
  446. #if defined(_EGL_OS_UNIX)
  447.    if (env && strchr(env, '/')) {
  448.       search_path = "";
  449.       if ((geteuid() != getuid() || getegid() != getgid())) {
  450.          _eglLog(_EGL_DEBUG,
  451.                "ignore EGL_DRIVER for setuid/setgid binaries");
  452.          env = NULL;
  453.       }
  454.    }
  455.    else if (env) {
  456.       char *suffix = strchr(env, '.');
  457.       name_len = (suffix) ? suffix - env : strlen(env);
  458.    }
  459. #else
  460.    if (env)
  461.       name_len = strlen(env);
  462. #endif /* _EGL_OS_UNIX */
  463.  
  464.    /*
  465.     * Try built-in drivers first if we know the driver name.  This makes sure
  466.     * we do not load the outdated external driver that is still on the
  467.     * filesystem.
  468.     */
  469.    if (name_len) {
  470.       _EGLModule *mod;
  471.       EGLint i;
  472.  
  473.       for (i = 0; _eglBuiltInDrivers[i].name; i++) {
  474.          if (strlen(_eglBuiltInDrivers[i].name) == name_len &&
  475.              !strncmp(_eglBuiltInDrivers[i].name, env, name_len)) {
  476.             mod = _eglAddModule(env);
  477.             if (mod)
  478.                mod->BuiltIn = _eglBuiltInDrivers[i].main;
  479.  
  480.             return EGL_TRUE;
  481.          }
  482.       }
  483.    }
  484.  
  485.    /* otherwise, treat env as a path */
  486.    if (env) {
  487.       _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
  488.  
  489.       return EGL_TRUE;
  490.    }
  491.  
  492.    return EGL_FALSE;
  493. }
  494.  
  495.  
  496. /**
  497.  * Add egl_gallium to the module array.
  498.  */
  499. static void
  500. _eglAddGalliumDriver(void)
  501. {
  502. #ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
  503.    void *external = (void *) "egl_gallium";
  504.    _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external);
  505. #endif
  506. }
  507. #endif
  508.  
  509.  
  510. /**
  511.  * Add built-in drivers to the module array.
  512.  */
  513. static void
  514. _eglAddBuiltInDrivers(void)
  515. {
  516.    _EGLModule *mod;
  517.    EGLint i;
  518.  
  519.    for (i = 0; _eglBuiltInDrivers[i].name; i++) {
  520.       mod = _eglAddModule(_eglBuiltInDrivers[i].name);
  521.       if (mod)
  522.          mod->BuiltIn = _eglBuiltInDrivers[i].main;
  523.    }
  524. }
  525.  
  526.  
  527. /**
  528.  * Add drivers to the module array.  Drivers will be loaded as they are matched
  529.  * to displays.
  530.  */
  531. static EGLBoolean
  532. _eglAddDrivers(void)
  533. {
  534.    if (_eglModules)
  535.       return EGL_TRUE;
  536.  
  537. //   if (!_eglAddUserDriver()) {
  538.       /*
  539.        * Add other drivers only when EGL_DRIVER is not set.  The order here
  540.        * decides the priorities.
  541.        */
  542. //      _eglAddGalliumDriver();
  543.       _eglAddBuiltInDrivers();
  544. //   }
  545.  
  546.    return (_eglModules != NULL);
  547. }
  548.  
  549.  
  550. /**
  551.  * A helper function for _eglMatchDriver.  It finds the first driver that can
  552.  * initialize the display and return.
  553.  */
  554. static _EGLDriver *
  555. _eglMatchAndInitialize(_EGLDisplay *dpy)
  556. {
  557.    _EGLDriver *drv = NULL;
  558.    EGLint i = 0;
  559.  
  560.    if (!_eglAddDrivers()) {
  561.       _eglLog(_EGL_WARNING, "failed to find any driver");
  562.       return NULL;
  563.    }
  564.  
  565.    if (dpy->Driver) {
  566.       drv = dpy->Driver;
  567.       /* no re-matching? */
  568.       if (!drv->API.Initialize(drv, dpy))
  569.          drv = NULL;
  570.       return drv;
  571.    }
  572.  
  573.    while (i < _eglModules->Size) {
  574.       _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
  575.  
  576.       if (!_eglLoadModule(mod)) {
  577.          /* remove invalid modules */
  578.          _eglEraseArray(_eglModules, i, _eglFreeModule);
  579.          continue;
  580.       }
  581.  
  582.       if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
  583.          drv = mod->Driver;
  584.          break;
  585.       }
  586.       else {
  587.          i++;
  588.       }
  589.    }
  590.  
  591.    return drv;
  592. }
  593.  
  594.  
  595. /**
  596.  * Match a display to a driver.  The display is initialized unless test_only is
  597.  * true.  The matching is done by finding the first driver that can initialize
  598.  * the display.
  599.  */
  600. _EGLDriver *
  601. _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
  602. {
  603.    _EGLDriver *best_drv;
  604.  
  605.    assert(!dpy->Initialized);
  606.  
  607.    _eglLockMutex(&_eglModuleMutex);
  608.  
  609.    /* set options */
  610.    dpy->Options.TestOnly = test_only;
  611.    dpy->Options.UseFallback = EGL_FALSE;
  612.  
  613.    best_drv = _eglMatchAndInitialize(dpy);
  614.    if (!best_drv) {
  615.       dpy->Options.UseFallback = EGL_TRUE;
  616.       best_drv = _eglMatchAndInitialize(dpy);
  617.    }
  618.  
  619.    _eglUnlockMutex(&_eglModuleMutex);
  620.  
  621.    if (best_drv) {
  622.       _eglLog(_EGL_DEBUG, "the best driver is %s%s",
  623.             best_drv->Name, (test_only) ? " (test only) " : "");
  624.       if (!test_only) {
  625.          dpy->Driver = best_drv;
  626.          dpy->Initialized = EGL_TRUE;
  627.       }
  628.    }
  629.  
  630.    return best_drv;
  631. }
  632.  
  633.  
  634. __eglMustCastToProperFunctionPointerType
  635. _eglGetDriverProc(const char *procname)
  636. {
  637.    EGLint i;
  638.    _EGLProc proc = NULL;
  639.  
  640.    if (!_eglModules) {
  641.       /* load the driver for the default display */
  642.       EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  643.       _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
  644.       if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
  645.          return NULL;
  646.    }
  647.  
  648.    for (i = 0; i < _eglModules->Size; i++) {
  649.       _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
  650.  
  651.       if (!mod->Driver)
  652.          break;
  653.       proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
  654.       if (proc)
  655.          break;
  656.    }
  657.  
  658.    return proc;
  659. }
  660.  
  661.  
  662. /**
  663.  * Unload all drivers.
  664.  */
  665. void
  666. _eglUnloadDrivers(void)
  667. {
  668.    /* this is called at atexit time */
  669.    if (_eglModules) {
  670.       _eglDestroyArray(_eglModules, _eglFreeModule);
  671.       _eglModules = NULL;
  672.    }
  673. }
  674.  
  675. #if 0
  676. /**
  677.  * Invoke a callback function on each EGL search path.
  678.  *
  679.  * The first argument of the callback function is the name of the search path.
  680.  * The second argument is the length of the name.
  681.  */
  682. void
  683. _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
  684.                       void *callback_data)
  685. {
  686.    const char *search_path = _eglGetSearchPath();
  687.    _eglPreloadForEach(search_path, callback, callback_data);
  688. }
  689. #endif
  690.