diff options
author | Chia-I Wu <[email protected]> | 2010-05-05 18:27:29 +0800 |
---|---|---|
committer | Chia-I Wu <[email protected]> | 2010-05-08 14:54:13 +0800 |
commit | 2773f888dc9cde61dedf1b004e35efcc72ca9240 (patch) | |
tree | a7f1631e82e8e908cdf402a75b3521ec2505b000 /src/gallium/state_trackers/egl | |
parent | e8ba2812e6995d1ec95c972a1b48ac29a99531dd (diff) |
egl_g3d: Check external modules for client APIs first.
dlopen api_<API>.so before dlopening the process itself in case the
client APIs are implemented in external modules.
Diffstat (limited to 'src/gallium/state_trackers/egl')
-rw-r--r-- | src/gallium/state_trackers/egl/common/egl_g3d.c | 9 | ||||
-rw-r--r-- | src/gallium/state_trackers/egl/common/egl_g3d_st.c | 180 | ||||
-rw-r--r-- | src/gallium/state_trackers/egl/common/egl_g3d_st.h | 7 |
3 files changed, 157 insertions, 39 deletions
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c index 3ab72dce2f3..5c6fe97922a 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d.c @@ -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); } diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_st.c b/src/gallium/state_trackers/egl/common/egl_g3d_st.c index 97445478684..1df57d07774 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_st.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_st.c @@ -27,8 +27,10 @@ */ #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 diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_st.h b/src/gallium/state_trackers/egl/common/egl_g3d_st.h index c82681a22d8..ee53799b029 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_st.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d_st.h @@ -33,8 +33,11 @@ #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); |