|
1 | 1 | /* |
2 | 2 | * Mesa libGL wrapper for macOS EGL using dlsym interposition |
| 3 | + * |
| 4 | + * This library intercepts dlsym calls to redirect GL function lookups |
| 5 | + * to Mesa's EGL implementation. It finds libEGL.dylib relative to itself, |
| 6 | + * making the install location-independent. |
| 7 | + * |
| 8 | + * It also sets MESA_EGL_LIBRARY and MESA_VULKAN_LIBRARY environment variables |
| 9 | + * so that GLFW and Zink can find the libraries when DYLD_LIBRARY_PATH is |
| 10 | + * stripped by SIP on macOS. |
3 | 11 | */ |
4 | 12 |
|
5 | 13 | #include <dlfcn.h> |
6 | 14 | #include <stdio.h> |
| 15 | +#include <stdlib.h> |
7 | 16 | #include <string.h> |
8 | 17 | #include <stddef.h> |
9 | 18 | #include <EGL/egl.h> |
|
16 | 25 | static void *egl_handle = NULL; |
17 | 26 | static PFNEGLGETPROCADDRESSPROC mesa_eglGetProcAddress = NULL; |
18 | 27 | static int initialized = 0; |
| 28 | +static int env_vars_set = 0; |
| 29 | +static char lib_dir[1024] = {0}; |
| 30 | +static char egl_lib_path[1024] = {0}; |
| 31 | + |
| 32 | +/* Determine the library directory and EGL path */ |
| 33 | +static void determine_paths(void) { |
| 34 | + if (lib_dir[0] != '\0') return; |
| 35 | + |
| 36 | + Dl_info info; |
| 37 | + if (dladdr((void*)determine_paths, &info) && info.dli_fname) { |
| 38 | + const char *last_slash = strrchr(info.dli_fname, '/'); |
| 39 | + if (last_slash) { |
| 40 | + size_t dir_len = last_slash - info.dli_fname; |
| 41 | + snprintf(lib_dir, sizeof(lib_dir), "%.*s", (int)dir_len, info.dli_fname); |
| 42 | + snprintf(egl_lib_path, sizeof(egl_lib_path), "%s/libEGL.dylib", lib_dir); |
| 43 | + } else { |
| 44 | + snprintf(egl_lib_path, sizeof(egl_lib_path), "libEGL.dylib"); |
| 45 | + } |
| 46 | + } else { |
| 47 | + snprintf(egl_lib_path, sizeof(egl_lib_path), "libEGL.dylib"); |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +/* Set environment variables for library paths (called lazily) */ |
| 52 | +static void set_env_vars(void) { |
| 53 | + if (env_vars_set) return; |
| 54 | + env_vars_set = 1; |
| 55 | + |
| 56 | + determine_paths(); |
| 57 | + |
| 58 | + /* Set EGL library path */ |
| 59 | + setenv("MESA_EGL_LIBRARY", egl_lib_path, 1); |
| 60 | + fprintf(stderr, "libGL interpose: Set MESA_EGL_LIBRARY=%s\n", egl_lib_path); |
| 61 | + |
| 62 | + /* Set Vulkan library path */ |
| 63 | + if (lib_dir[0] != '\0') { |
| 64 | + char vk_lib_path[1024]; |
| 65 | + snprintf(vk_lib_path, sizeof(vk_lib_path), "%s/libvulkan.1.dylib", lib_dir); |
| 66 | + setenv("MESA_VULKAN_LIBRARY", vk_lib_path, 1); |
| 67 | + fprintf(stderr, "libGL interpose: Set MESA_VULKAN_LIBRARY=%s\n", vk_lib_path); |
| 68 | + } |
| 69 | +} |
19 | 70 |
|
20 | 71 | static void ensure_initialized(void) { |
21 | 72 | if (initialized) return; |
22 | 73 | initialized = 1; |
23 | 74 |
|
24 | | - egl_handle = dlopen("/Users/lucamignatti/mesa-native/lib/libEGL.dylib", RTLD_NOW | RTLD_LOCAL); |
| 75 | + determine_paths(); |
| 76 | + set_env_vars(); |
| 77 | + |
| 78 | + egl_handle = dlopen(egl_lib_path, RTLD_NOW | RTLD_LOCAL); |
25 | 79 | if (egl_handle) { |
26 | | - fprintf(stderr, "libGL interpose: Loaded Mesa EGL\n"); |
| 80 | + fprintf(stderr, "libGL interpose: Loaded Mesa EGL from %s\n", egl_lib_path); |
27 | 81 | mesa_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)dlsym(egl_handle, "eglGetProcAddress"); |
28 | 82 | if (mesa_eglGetProcAddress) { |
29 | 83 | fprintf(stderr, "libGL interpose: Ready to forward GL calls\n"); |
30 | 84 | } |
| 85 | + } else { |
| 86 | + fprintf(stderr, "libGL interpose: Failed to load %s: %s\n", egl_lib_path, dlerror()); |
31 | 87 | } |
32 | 88 | } |
33 | 89 |
|
34 | 90 | /* Interpose dlsym to catch GL function lookups */ |
35 | | -void *my_dlsym(void *handle, const char *symbol) { |
| 91 | +static void *my_dlsym(void *handle, const char *symbol) { |
| 92 | + /* Set env vars early so other libraries can use them */ |
| 93 | + if (!env_vars_set) { |
| 94 | + set_env_vars(); |
| 95 | + } |
| 96 | + |
36 | 97 | ensure_initialized(); |
37 | 98 |
|
38 | 99 | /* If looking for a GL function, use eglGetProcAddress */ |
|
0 commit comments