]> git.cworth.org Git - glaze/blob - glaze-gl.c
Add egl definitions and related buildsupport.
[glaze] / glaze-gl.c
1 /* Copyright © 2013, Intel Corporation
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 #define _GNU_SOURCE
23 #include <dlfcn.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <fcntl.h>
30
31 void *libgl_handle;
32 void **wrapper_handles;
33 int num_wrapper_handles;
34
35 #define STRNCMP_LITERAL(str, literal) strncmp (str, literal, sizeof (literal) - 1)
36
37 static void
38 open_libgl_handle (void)
39 {
40         const char *libgl_path;
41
42         if (libgl_handle)
43                 return;
44
45         libgl_path = getenv ("GLAZE_LIBGL");
46
47         if (libgl_path == NULL) {
48
49 #if GLAZE_BITS == 32
50                 libgl_path = getenv ("GLAZE_LIBGL_32_AUTO");
51 #elif GLAZE_BITS == 64
52                 libgl_path = getenv ("GLAZE_LIBGL_64_AUTO");
53 #endif
54
55                 if (libgl_path == NULL || strlen (libgl_path) == 0) {
56                         fprintf (stderr,
57                                  "Error: Failed to detect OpenGL library.\n"
58                                  "Please set GLAZE_LIBGL to path of real libGL.so\n");
59                         exit (1);
60                 }
61
62                 setenv ("GLAZE_LIBGL", libgl_path, 1);
63         }
64
65         dlerror();
66         libgl_handle = dlopen (libgl_path, RTLD_LAZY | RTLD_GLOBAL);
67         if (libgl_handle == NULL) {
68                 fprintf (stderr, "glaze_init: Error: Failed to dlopen %s: %s\n",
69                          libgl_path, dlerror());
70                 exit (1);
71         }
72 }
73
74 /* Count the number of types 'chr' appears in 'str' */
75 static int
76 count_chars (const char *str, char chr)
77 {
78         int count = 0;
79         const char *s = str;
80
81         while (1) {
82                 s = strchr (s, chr);
83                 if (s == NULL)
84                         break;
85                 count++;
86                 s++;
87                 if (*s == '\0')
88                         break;
89         }
90
91         return count;
92 }
93
94 static void
95 open_wrapper_handles (void)
96 {
97         const char *path;
98         char *path_copy, *wrapper, *save;
99         int i;
100
101         if (wrapper_handles)
102                 return;
103
104         path = getenv ("GLAZE_WRAPPER");
105         if (path == NULL) {
106                 fprintf (stderr, "GLAZE_WRAPPER unset. Please set to path of Glaze-using wrapper library.\n");
107                 exit (1);
108         }
109
110         num_wrapper_handles = count_chars (path, ':') + 1;
111
112         wrapper_handles = malloc (num_wrapper_handles * sizeof (void*));
113         if (wrapper_handles == NULL) {
114                 fprintf (stderr, "Out of memory\n");
115                 exit (1);
116         }
117
118         /* Clear dlerror state. */
119         dlerror ();
120
121         path_copy = strdup (path);
122         if (path_copy == NULL) {
123                 fprintf (stderr, "Out of memory\n");
124                 exit (1);
125         }
126
127         for (i = 0, wrapper = strtok_r (path_copy, ":", &save);
128              i < num_wrapper_handles;
129              i++, wrapper = strtok_r (NULL, ":", &save))
130         {
131                 wrapper_handles[i] = dlopen (wrapper, RTLD_LAZY);
132                 if (wrapper_handles[i] == NULL) {
133                         const char *error = dlerror();
134                         fprintf (stderr, "Error: Failed to dlopen %s: %s\n",
135                                  wrapper, error);
136                         exit (1);
137                 }
138         }
139
140         free (path_copy);
141 }
142
143 static void
144 glaze_init (void) __attribute__((constructor));
145
146 static void
147 glaze_init (void)
148 {
149         open_libgl_handle ();
150         open_wrapper_handles ();
151 }
152
153 static void
154 call_first_gl_call_callbacks (void)
155 {
156         char *callbacks = getenv ("GLAZE_FIRST_GL_CALL_CALLBACK");
157         char *name, *names, *save;
158         void (*callback) (void);
159         int i;
160
161         if (callbacks == NULL)
162                 return;
163
164         names = strdup (callbacks);
165         if (names == NULL) {
166                 fprintf (stderr, "Out of memory\n");
167                 exit (1);
168         }
169
170         for (name = strtok_r (names, ":", &save);
171              name;
172              name = strtok_r (NULL, ":", &save))
173         {
174                 for (i = 0; i < num_wrapper_handles; i++) {
175                         callback = dlsym (wrapper_handles[i], name);
176                         if (callback) {
177                                 (callback) ();
178                                 goto NEXT_NAME;
179                         }
180                 }
181                 fprintf (stderr, "Error: Failed to find function %s "
182                          "in any GLAZE_WRAPPER library.\n", name);
183         NEXT_NAME:
184                 ;
185         }
186
187         free (names);
188 }
189
190 static void *
191 find_symbol_in_glaze_wrappers (const char *name)
192 {
193         void *symbol;
194         int i;
195
196         for (i = 0; i < num_wrapper_handles; i++) {
197                 symbol = dlsym (wrapper_handles[i], name);
198                 if (symbol)
199                         return symbol;
200         }
201
202         return NULL;
203 }
204
205 static void *
206 resolve (const char *name)
207 {
208         static int before_first_gl_call = 1;
209         void *symbol;
210
211         if (before_first_gl_call &&
212             STRNCMP_LITERAL (name, "gl") == 0 &&
213             STRNCMP_LITERAL (name, "glX") != 0)
214         {
215                 call_first_gl_call_callbacks ();
216
217                 before_first_gl_call = 0;
218         }
219
220         /* The wrappers get first choice on all symbols. */
221         symbol = find_symbol_in_glaze_wrappers (name);
222         if (symbol)
223                 return symbol;
224
225         return dlsym (libgl_handle, name);
226 }
227
228 void
229 (*glXGetProcAddress (const unsigned char *name))(void);
230
231 void
232 (*glXGetProcAddress (const unsigned char *name))(void)
233 {
234         static int first_call = 1;
235         static typeof (&glXGetProcAddress) wrapper_glXGetProcAddress;
236         static typeof (&glXGetProcAddress) libgl_glXGetProcAddress;
237         void *symbol;
238
239         /* On the first call, check if the wrapper provides an
240          * implementation of this function. */
241         if (first_call) {
242                 wrapper_glXGetProcAddress =
243                         find_symbol_in_glaze_wrappers ("glXGetProcAddress");
244                 libgl_glXGetProcAddress = dlsym (libgl_handle,
245                                                  "glXGetProcAddress");
246                 first_call = 0;
247         }
248
249         /* If the wrapper implements glXGetProcAddress itself, then it
250          * had better know best what to do. Just let it. */
251         if (wrapper_glXGetProcAddress)
252                 return wrapper_glXGetProcAddress (name);
253
254         /* Otherwise, we need to resolve the name.
255          *
256          * The wrappers get first choice on all symbols. */
257         symbol = find_symbol_in_glaze_wrappers ((char *) name);
258         if (symbol)
259                 return symbol;
260
261         /* The wrapper doesn't care, so defer to the underlying
262          * glXGetProcAddress */
263         return libgl_glXGetProcAddress (name);
264
265 }
266
267 void
268 (*glXGetProcAddressARB (const unsigned char *name))(void);
269
270 void
271 (*glXGetProcAddressARB (const unsigned char *name))(void)
272 {
273         static int first_call = 1;
274         static typeof (&glXGetProcAddressARB) wrapper_glXGetProcAddressARB;
275         static typeof (&glXGetProcAddressARB) libgl_glXGetProcAddressARB;
276         void *symbol;
277
278         /* On the first call, check if the wrapper provides an
279          * implementation of this function. */
280         if (first_call) {
281                 wrapper_glXGetProcAddressARB =
282                         find_symbol_in_glaze_wrappers ("glXGetProcAddressARB");
283                 libgl_glXGetProcAddressARB = dlsym (libgl_handle,
284                                                     "glXGetProcAddressARB");
285                 first_call = 0;
286         }
287
288         /* If the wrapper implements glXGetProcAddressARB itself, then
289          * it had better know best what to do. Just let it. */
290         if (wrapper_glXGetProcAddressARB)
291                 return wrapper_glXGetProcAddressARB (name);
292
293         /* Otherwise, we need to resolve the name.
294          *
295          * The wrappers get first choice on all symbols. */
296         symbol = find_symbol_in_glaze_wrappers ((char *) name);
297         if (symbol)
298                 return symbol;
299
300         /* The wrapper doesn't care, so defer to the underlying
301          * glXGetProcAddressARB */
302         return libgl_glXGetProcAddressARB (name);
303
304 }
305
306 #define GLAZE_API(name)                                                 \
307 void * name() __attribute__((ifunc(#name "_resolver")));                \
308 static void *                                                           \
309 name ## _resolver (void) { return resolve (#name); }
310
311 #include "specs/gl.def"
312 #include "specs/glx.def"