#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)
static void
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");
}
}
+/* 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");
if (path == NULL) {
- fprintf (stderr, "GLAZE_WRAPPER unset. Please set to path of real libGL.so under glaze.\n");
+ fprintf (stderr, "GLAZE_WRAPPER unset. Please set to path of Glaze-using wrapper library.\n");
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
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 *
resolve (const char *name)
{
+ static int before_first_gl_call = 1;
void *symbol;
- /* The wrapper gets first choice on all symbols. */
- symbol = dlsym (wrapper_handle, name);
+ if (before_first_gl_call &&
+ STRNCMP_LITERAL (name, "gl") == 0 &&
+ STRNCMP_LITERAL (name, "glX") != 0)
+ {
+ call_first_gl_call_callbacks ();
+
+ before_first_gl_call = 0;
+ }
+
+ /* 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 * \