egl_dri2: Export glapi symbols for DRI drivers.
authorChia-I Wu <olv@lunarg.com>
Sat, 29 Jan 2011 21:09:06 +0000 (05:09 +0800)
committerChia-I Wu <olv@lunarg.com>
Sat, 29 Jan 2011 21:28:24 +0000 (05:28 +0800)
When an app loads libEGL.so dynamically with RTLD_LOCAL, loading DRI
drivers would fail because of missing glapi symbols.  This commit makes
egl_dri2 load libglapi.so with RTLD_GLOBAL to export glapi symbols for
future symbol resolutions.

The same trick can be found in GLX.  However, egl_dri2 can only do so
when --enable-shared-glapi is given.  Because, otherwise, both libGL.so
and libglapi.so define glapi symbols and egl_dri2 cannot tell which
library to load.

src/egl/drivers/dri2/Makefile
src/egl/drivers/dri2/egl_dri2.c

index 553ee8771f8457a932e989a2438b3a670b3a896f..bd3d70293370e2c2581324b1c4b6537296d5fdc4 100644 (file)
@@ -20,4 +20,8 @@ EGL_LIBS = $(XCB_DRI2_LIBS) $(LIBUDEV_LIBS) $(DLOPEN_LIBS) $(LIBDRM_LIB)
 EGL_CFLAGS = -D_EGL_MAIN=_eglBuiltInDriverDRI2
 EGL_BUILTIN = true
 
+ifeq ($(SHARED_GLAPI),1)
+EGL_CFLAGS += -DHAVE_SHARED_GLAPI
+endif
+
 include ../Makefile.template
index 6fc1e49e773e08b8ed117d0b19c1401b32ea9a8f..92fc9df54a8f43aa48eb5e4784a22975ecf987f1 100644 (file)
@@ -62,6 +62,7 @@ struct dri2_egl_driver
 {
    _EGLDriver base;
 
+   void *handle;
    _EGLProc (*get_proc_address)(const char *procname);
    void (*glFlush)(void);
 };
@@ -2337,6 +2338,9 @@ static void
 dri2_unload(_EGLDriver *drv)
 {
    struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
+
+   if (dri2_drv->handle)
+      dlclose(dri2_drv->handle);
    free(dri2_drv);
 }
 
@@ -2344,23 +2348,30 @@ static EGLBoolean
 dri2_load(_EGLDriver *drv)
 {
    struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
+#ifdef HAVE_SHARED_GLAPI
+   const char *libname = "libglapi.so.0";
+#else
+   /*
+    * Both libGL.so and libglapi.so are glapi providers.  There is no way to
+    * tell which one to load.
+    */
+   const char *libname = NULL;
+#endif
    void *handle;
 
-   handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
+   /* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */
+   handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
    if (handle) {
       dri2_drv->get_proc_address = (_EGLProc (*)(const char *))
          dlsym(handle, "_glapi_get_proc_address");
-      /* no need to keep a reference */
-      dlclose(handle);
+      if (!dri2_drv->get_proc_address || !libname) {
+         /* no need to keep a reference */
+         dlclose(handle);
+         handle = NULL;
+      }
    }
 
-   /*
-    * If glapi is not available, loading DRI drivers will fail.  Ideally, we
-    * should load one of libGL, libGLESv1_CM, or libGLESv2 and go on.  But if
-    * the app has loaded another one of them with RTLD_LOCAL, there may be
-    * unexpected behaviors later because there will be two copies of glapi
-    * (with global variables of the same names!) in the memory.
-    */
+   /* if glapi is not available, loading DRI drivers will fail */
    if (!dri2_drv->get_proc_address) {
       _eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address");
       return EGL_FALSE;
@@ -2369,6 +2380,8 @@ dri2_load(_EGLDriver *drv)
    dri2_drv->glFlush = (void (*)(void))
       dri2_drv->get_proc_address("glFlush");
 
+   dri2_drv->handle = handle;
+
    return EGL_TRUE;
 }