]> git.cworth.org Git - glaze/blobdiff - glaze-gl.c
Add egl definitions and related buildsupport.
[glaze] / glaze-gl.c
index 14d24d76c1bb875e4bd19a84fa39d675cf3460e1..8c3a82d883e4c2055e960fc5ba9d3eaada3913f5 100644 (file)
@@ -29,7 +29,8 @@
 #include <fcntl.h>
 
 void *libgl_handle;
-void *wrapper_handle;
+void **wrapper_handles;
+int num_wrapper_handles;
 
 #define STRNCMP_LITERAL(str, literal) strncmp (str, literal, sizeof (literal) - 1)
 
@@ -51,7 +52,7 @@ open_libgl_handle (void)
                libgl_path = getenv ("GLAZE_LIBGL_64_AUTO");
 #endif
 
-               if (libgl_path == NULL) {
+               if (libgl_path == NULL || strlen (libgl_path) == 0) {
                        fprintf (stderr,
                                 "Error: Failed to detect OpenGL library.\n"
                                 "Please set GLAZE_LIBGL to path of real libGL.so\n");
@@ -70,12 +71,34 @@ open_libgl_handle (void)
        }
 }
 
+/* Count the number of types 'chr' appears in 'str' */
+static int
+count_chars (const char *str, char chr)
+{
+       int count = 0;
+       const char *s = str;
+
+       while (1) {
+               s = strchr (s, chr);
+               if (s == NULL)
+                       break;
+               count++;
+               s++;
+               if (*s == '\0')
+                       break;
+       }
+
+       return count;
+}
+
 static void
-open_wrapper_handle (void)
+open_wrapper_handles (void)
 {
        const char *path;
+       char *path_copy, *wrapper, *save;
+       int i;
 
-       if (wrapper_handle)
+       if (wrapper_handles)
                return;
 
        path = getenv ("GLAZE_WRAPPER");
@@ -84,13 +107,37 @@ open_wrapper_handle (void)
                exit (1);
        }
 
+       num_wrapper_handles = count_chars (path, ':') + 1;
+
+       wrapper_handles = malloc (num_wrapper_handles * sizeof (void*));
+       if (wrapper_handles == NULL) {
+               fprintf (stderr, "Out of memory\n");
+               exit (1);
+       }
+
+       /* Clear dlerror state. */
        dlerror ();
-       wrapper_handle = dlopen (path, RTLD_LAZY);
-       if (wrapper_handle == NULL) {
-               const char *error = dlerror();
-               fprintf (stderr, "Error: Failed to dlopen %s: %s\n", path, error);
+
+       path_copy = strdup (path);
+       if (path_copy == NULL) {
+               fprintf (stderr, "Out of memory\n");
                exit (1);
        }
+
+       for (i = 0, wrapper = strtok_r (path_copy, ":", &save);
+            i < num_wrapper_handles;
+            i++, wrapper = strtok_r (NULL, ":", &save))
+       {
+               wrapper_handles[i] = dlopen (wrapper, RTLD_LAZY);
+               if (wrapper_handles[i] == NULL) {
+                       const char *error = dlerror();
+                       fprintf (stderr, "Error: Failed to dlopen %s: %s\n",
+                                wrapper, error);
+                       exit (1);
+               }
+       }
+
+       free (path_copy);
 }
 
 static void
@@ -100,7 +147,59 @@ static void
 glaze_init (void)
 {
        open_libgl_handle ();
-       open_wrapper_handle ();
+       open_wrapper_handles ();
+}
+
+static void
+call_first_gl_call_callbacks (void)
+{
+       char *callbacks = getenv ("GLAZE_FIRST_GL_CALL_CALLBACK");
+       char *name, *names, *save;
+       void (*callback) (void);
+       int i;
+
+       if (callbacks == NULL)
+               return;
+
+       names = strdup (callbacks);
+       if (names == NULL) {
+               fprintf (stderr, "Out of memory\n");
+               exit (1);
+       }
+
+       for (name = strtok_r (names, ":", &save);
+            name;
+            name = strtok_r (NULL, ":", &save))
+       {
+               for (i = 0; i < num_wrapper_handles; i++) {
+                       callback = dlsym (wrapper_handles[i], name);
+                       if (callback) {
+                               (callback) ();
+                               goto NEXT_NAME;
+                       }
+               }
+               fprintf (stderr, "Error: Failed to find function %s "
+                        "in any GLAZE_WRAPPER library.\n", name);
+       NEXT_NAME:
+               ;
+       }
+
+       free (names);
+}
+
+static void *
+find_symbol_in_glaze_wrappers (const char *name)
+{
+       void *symbol;
+       int i;
+
+       for (i = 0; i < num_wrapper_handles; i++) {
+               symbol = dlsym (wrapper_handles[i], name);
+               if (symbol)
+                       return symbol;
+       }
+
+       return NULL;
 }
 
 static void *
@@ -113,30 +212,97 @@ resolve (const char *name)
            STRNCMP_LITERAL (name, "gl") == 0 &&
            STRNCMP_LITERAL (name, "glX") != 0)
        {
-               char *callback_name = getenv ("GLAZE_FIRST_GL_CALL_CALLBACK");
-               if (callback_name) {
-                       void (*callback) (void) = dlsym (wrapper_handle,
-                                                        callback_name);
-                       if (callback) {
-                               (callback) ();
-                       } else {
-                               fprintf (stderr,
-                                        "Error: Failed to find function %s "
-                                        "in GLAZE_WRAPPER library.\n",
-                                        callback_name);
-                       }
-               }
+               call_first_gl_call_callbacks ();
+
                before_first_gl_call = 0;
        }
 
-       /* The wrapper gets first choice on all symbols. */
-       symbol = dlsym (wrapper_handle, name);
+       /* The wrappers get first choice on all symbols. */
+       symbol = find_symbol_in_glaze_wrappers (name);
        if (symbol)
                return symbol;
 
        return dlsym (libgl_handle, name);
 }
 
+void
+(*glXGetProcAddress (const unsigned char *name))(void);
+
+void
+(*glXGetProcAddress (const unsigned char *name))(void)
+{
+       static int first_call = 1;
+       static typeof (&glXGetProcAddress) wrapper_glXGetProcAddress;
+       static typeof (&glXGetProcAddress) libgl_glXGetProcAddress;
+       void *symbol;
+
+       /* On the first call, check if the wrapper provides an
+        * implementation of this function. */
+       if (first_call) {
+               wrapper_glXGetProcAddress =
+                       find_symbol_in_glaze_wrappers ("glXGetProcAddress");
+               libgl_glXGetProcAddress = dlsym (libgl_handle,
+                                                "glXGetProcAddress");
+               first_call = 0;
+       }
+
+       /* If the wrapper implements glXGetProcAddress itself, then it
+        * had better know best what to do. Just let it. */
+       if (wrapper_glXGetProcAddress)
+               return wrapper_glXGetProcAddress (name);
+
+       /* Otherwise, we need to resolve the name.
+        *
+        * The wrappers get first choice on all symbols. */
+       symbol = find_symbol_in_glaze_wrappers ((char *) name);
+       if (symbol)
+               return symbol;
+
+       /* The wrapper doesn't care, so defer to the underlying
+        * glXGetProcAddress */
+       return libgl_glXGetProcAddress (name);
+
+}
+
+void
+(*glXGetProcAddressARB (const unsigned char *name))(void);
+
+void
+(*glXGetProcAddressARB (const unsigned char *name))(void)
+{
+       static int first_call = 1;
+       static typeof (&glXGetProcAddressARB) wrapper_glXGetProcAddressARB;
+       static typeof (&glXGetProcAddressARB) libgl_glXGetProcAddressARB;
+       void *symbol;
+
+       /* On the first call, check if the wrapper provides an
+        * implementation of this function. */
+       if (first_call) {
+               wrapper_glXGetProcAddressARB =
+                       find_symbol_in_glaze_wrappers ("glXGetProcAddressARB");
+               libgl_glXGetProcAddressARB = dlsym (libgl_handle,
+                                                   "glXGetProcAddressARB");
+               first_call = 0;
+       }
+
+       /* If the wrapper implements glXGetProcAddressARB itself, then
+        * it had better know best what to do. Just let it. */
+       if (wrapper_glXGetProcAddressARB)
+               return wrapper_glXGetProcAddressARB (name);
+
+       /* Otherwise, we need to resolve the name.
+        *
+        * The wrappers get first choice on all symbols. */
+       symbol = find_symbol_in_glaze_wrappers ((char *) name);
+       if (symbol)
+               return symbol;
+
+       /* The wrapper doesn't care, so defer to the underlying
+        * glXGetProcAddressARB */
+       return libgl_glXGetProcAddressARB (name);
+
+}
+
 #define GLAZE_API(name)                                                        \
 void * name() __attribute__((ifunc(#name "_resolver")));               \
 static void *                                                          \