X-Git-Url: https://git.cworth.org/git?p=glaze;a=blobdiff_plain;f=glaze-gl.c;h=8c3a82d883e4c2055e960fc5ba9d3eaada3913f5;hp=b6e7d72d3f8f9317a4ae03136f73b1ff9f444fa7;hb=HEAD;hpb=2b7630a8f3277a568695fc59996c8bad34261454 diff --git a/glaze-gl.c b/glaze-gl.c index b6e7d72..8c3a82d 100644 --- a/glaze-gl.c +++ b/glaze-gl.c @@ -24,52 +24,120 @@ #include #include +#include + +#include 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) { - const char *path; + const char *libgl_path; if (libgl_handle) return; - path = getenv ("GLAZE_LIBGL"); - if (path == NULL) { - fprintf (stderr, "GLAZE_LIBGL unset. Please set to path of real libGL.so under glaze.\n"); - exit (1); + libgl_path = getenv ("GLAZE_LIBGL"); + + if (libgl_path == NULL) { + +#if GLAZE_BITS == 32 + libgl_path = getenv ("GLAZE_LIBGL_32_AUTO"); +#elif GLAZE_BITS == 64 + libgl_path = getenv ("GLAZE_LIBGL_64_AUTO"); +#endif + + 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"); + exit (1); + } + + setenv ("GLAZE_LIBGL", libgl_path, 1); } - libgl_handle = dlopen (path, RTLD_LAZY | RTLD_GLOBAL); + dlerror(); + libgl_handle = dlopen (libgl_path, RTLD_LAZY | RTLD_GLOBAL); if (libgl_handle == NULL) { - fprintf (stderr, "Error: Failed to dlopen %s\n", path); + fprintf (stderr, "glaze_init: Error: Failed to dlopen %s: %s\n", + libgl_path, dlerror()); exit (1); } } +/* 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 @@ -79,22 +147,162 @@ 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 * \