egl_g3d: Check external modules for client APIs first.
authorChia-I Wu <olv@lunarg.com>
Wed, 5 May 2010 10:27:29 +0000 (18:27 +0800)
committerChia-I Wu <olv@lunarg.com>
Sat, 8 May 2010 06:54:13 +0000 (14:54 +0800)
dlopen api_<API>.so before dlopening the process itself in case the
client APIs are implemented in external modules.

src/gallium/state_trackers/egl/common/egl_g3d.c
src/gallium/state_trackers/egl/common/egl_g3d_st.c
src/gallium/state_trackers/egl/common/egl_g3d_st.h

index 3ab72dce2f3c126d3432208e99e276c468c33db7..5c6fe97922a7bf0944b29121f2eb07a71cddb7ad 100644 (file)
@@ -50,8 +50,8 @@ egl_g3d_init_st(_EGLDriver *drv)
    if (gdrv->api_mask)
       return;
 
+   egl_g3d_init_st_apis(gdrv->stapis);
    for (i = 0; i < ST_API_COUNT; i++) {
-      gdrv->stapis[i] = egl_g3d_create_st_api(i);
       if (gdrv->stapis[i])
          gdrv->api_mask |= egl_g3d_st_api_bit(i);
    }
@@ -581,13 +581,8 @@ static void
 egl_g3d_unload(_EGLDriver *drv)
 {
    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
-   EGLint i;
-
-   for (i = 0; i < ST_API_COUNT; i++) {
-      if (gdrv->stapis[i])
-         gdrv->stapis[i]->destroy(gdrv->stapis[i]);
-   }
 
+   egl_g3d_destroy_st_apis();
    egl_g3d_destroy_probe(drv, NULL);
    FREE(gdrv);
 }
index 97445478684f1e772fb63f0359c5d36042e3e4cd..1df57d0777490ccc63cd5cf659e44e23f18e9a11 100644 (file)
  */
 
 #include "util/u_memory.h"
+#include "util/u_string.h"
 #include "util/u_inlines.h"
 #include "util/u_dl.h"
+#include "egldriver.h"
 #include "eglimage.h"
 #include "eglmutex.h"
 
@@ -46,42 +48,160 @@ egl_g3d_st_manager(struct st_manager *smapi)
    return (struct egl_g3d_st_manager *) smapi;
 }
 
-struct st_api *
-egl_g3d_create_st_api(enum st_api_type api)
-{
+static struct egl_g3d_st_module {
+   const char *filename;
    struct util_dl_library *lib;
-   const char *proc_name;
-   struct st_api * (*proc)(void) = NULL;
-
-   switch (api) {
-   case ST_API_OPENGL:
-      proc_name = ST_CREATE_OPENGL_SYMBOL;
-      break;
-   case ST_API_OPENGL_ES1:
-      proc_name = ST_CREATE_OPENGL_ES1_SYMBOL;
-      break;
-   case ST_API_OPENGL_ES2:
-      proc_name = ST_CREATE_OPENGL_ES2_SYMBOL;
-      break;
-   case ST_API_OPENVG:
-      proc_name = ST_CREATE_OPENVG_SYMBOL;
-      break;
-   default:
-      assert(!"Unknown API Type\n");
-      return NULL;
+   struct st_api *stapi;
+} egl_g3d_st_modules[ST_API_COUNT];
+
+static EGLBoolean
+egl_g3d_search_path_callback(const char *dir, size_t len, void *callback_data)
+{
+   struct egl_g3d_st_module *stmod =
+      (struct egl_g3d_st_module *) callback_data;
+   char path[1024];
+   int ret;
+
+   ret = util_snprintf(path, sizeof(path),
+         "%.*s/%s", len, dir, stmod->filename);
+   if (ret > 0 && ret < sizeof(path))
+      stmod->lib = util_dl_open(path);
+
+   return !(stmod->lib);
+}
+
+static boolean
+egl_g3d_load_st_module(struct egl_g3d_st_module *stmod,
+                       const char *filename, const char *procname)
+{
+   struct st_api *(*create_api)(void);
+
+   stmod->filename = filename;
+   if (stmod->filename)
+      _eglSearchPathForEach(egl_g3d_search_path_callback, (void *) stmod);
+   else
+      stmod->lib = util_dl_open(NULL);
+
+   if (stmod->lib) {
+      create_api = (struct st_api *(*)(void))
+         util_dl_get_proc_address(stmod->lib, procname);
+      if (create_api)
+         stmod->stapi = create_api();
+
+      if (!stmod->stapi) {
+         util_dl_close(stmod->lib);
+         stmod->lib = NULL;
+      }
    }
 
-   lib = util_dl_open(NULL);
-   if (lib) {
-      proc = util_dl_get_proc_address(lib, proc_name);
-      debug_printf("%s: %s %p\n", __func__, proc_name, proc);
-      util_dl_close(lib);
+   if (stmod->stapi) {
+      return TRUE;
    }
+   else {
+      stmod->filename = NULL;
+      return FALSE;
+   }
+}
 
-   if (!proc)
-      return NULL;
+void
+egl_g3d_init_st_apis(struct st_api *stapis[ST_API_COUNT])
+{
+   const char *skip_checks[ST_API_COUNT], *symbols[ST_API_COUNT];
+   const char *filenames[ST_API_COUNT][4];
+   struct util_dl_library *self;
+   int num_needed = 0, api;
+
+   self = util_dl_open(NULL);
+
+   /* collect the necessary data for loading modules */
+   for (api = 0; api < ST_API_COUNT; api++) {
+      int count = 0;
+
+      switch (api) {
+      case ST_API_OPENGL:
+         skip_checks[api] = "glColor4d";
+         symbols[api] = ST_CREATE_OPENGL_SYMBOL;
+         filenames[api][count++] = "api_GL.so";
+         break;
+      case ST_API_OPENGL_ES1:
+         skip_checks[api] = "glColor4x";
+         symbols[api] = ST_CREATE_OPENGL_ES1_SYMBOL;
+         filenames[api][count++] = "api_GLESv1_CM.so";
+         filenames[api][count++] = "api_GL.so";
+         break;
+      case ST_API_OPENGL_ES2:
+         skip_checks[api] = "glShaderBinary";
+         symbols[api] = ST_CREATE_OPENGL_ES2_SYMBOL;
+         filenames[api][count++] = "api_GLESv2.so";
+         filenames[api][count++] = "api_GL.so";
+         break;
+      case ST_API_OPENVG:
+         skip_checks[api] = "vgClear";
+         symbols[api] = ST_CREATE_OPENVG_SYMBOL;
+         filenames[api][count++]= "api_OpenVG.so";
+         break;
+      default:
+         assert(!"Unknown API Type\n");
+         skip_checks[api] = NULL;
+         symbols[api] = NULL;
+         break;
+      }
+      filenames[api][count++]= NULL;
+      assert(count < Elements(filenames[api]));
+
+      /* heuristicically decide if the module is needed */
+      if (!self || !skip_checks[api] ||
+          util_dl_get_proc_address(self, skip_checks[api])) {
+         /* unset so the module is not skipped */
+         skip_checks[api] = NULL;
+         num_needed++;
+      }
+   }
+   /* mark all moudles needed if we wrongly decided that none is needed */
+   if (!num_needed)
+      memset(skip_checks, 0, sizeof(skip_checks));
+
+   if (self)
+      util_dl_close(self);
+
+   for (api = 0; api < ST_API_COUNT; api++) {
+      struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
+      const char **p;
+
+      /* skip the module */
+      if (skip_checks[api])
+         continue;
+
+      /* try all filenames, including NULL */
+      for (p = filenames[api]; *p; p++) {
+         if (egl_g3d_load_st_module(stmod, *p, symbols[api]))
+            break;
+      }
+      if (!stmod->stapi)
+         egl_g3d_load_st_module(stmod, NULL, symbols[api]);
 
-   return proc();
+      stapis[api] = stmod->stapi;
+   }
+}
+
+void
+egl_g3d_destroy_st_apis(void)
+{
+   int api;
+
+   for (api = 0; api < ST_API_COUNT; api++) {
+      struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
+
+      if (stmod->stapi) {
+         stmod->stapi->destroy(stmod->stapi);
+         stmod->stapi = NULL;
+      }
+      if (stmod->lib) {
+         util_dl_close(stmod->lib);
+         stmod->lib = NULL;
+      }
+      stmod->filename = NULL;
+   }
 }
 
 static boolean
index c82681a22d8d896a30eadc6017bcdfc3385a4628..ee53799b0297a9103abd8272281c7728afe633a6 100644 (file)
 #include "state_tracker/st_api.h"
 #include "egltypedefs.h"
 
-struct st_api *
-egl_g3d_create_st_api(enum st_api_type api);
+void
+egl_g3d_init_st_apis(struct st_api *stapis[ST_API_COUNT]);
+
+void
+egl_g3d_destroy_st_apis(void);
 
 struct st_manager *
 egl_g3d_create_st_manager(_EGLDisplay *dpy);