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