1 /*
2  * Copyright © 2013-2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /**
25  * \mainpage Epoxy
26  *
27  * \section intro_sec Introduction
28  *
29  * Epoxy is a library for handling OpenGL function pointer management for
30  * you.
31  *
32  * It hides the complexity of `dlopen()`, `dlsym()`, `glXGetProcAddress()`,
33  * `eglGetProcAddress()`, etc. from the app developer, with very little
34  * knowledge needed on their part.  They get to read GL specs and write
35  * code using undecorated function names like `glCompileShader()`.
36  *
37  * Don't forget to check for your extensions or versions being present
38  * before you use them, just like before!  We'll tell you what you forgot
39  * to check for instead of just segfaulting, though.
40  *
41  * \section features_sec Features
42  *
43  *   - Automatically initializes as new GL functions are used.
44  *   - GL 4.6 core and compatibility context support.
45  *   - GLES 1/2/3 context support.
46  *   - Knows about function aliases so (e.g.) `glBufferData()` can be
47  *     used with `GL_ARB_vertex_buffer_object` implementations, along
48  *     with GL 1.5+ implementations.
49  *   - EGL, GLX, and WGL support.
50  *   - Can be mixed with non-epoxy GL usage.
51  *
52  * \section using_sec Using Epoxy
53  *
54  * Using Epoxy should be as easy as replacing:
55  *
56  * ```cpp
57  * #include <GL/gl.h>
58  * #include <GL/glx.h>
59  * #include <GL/glext.h>
60  * ```
61  *
62  * with:
63  *
64  * ```cpp
65  * #include <epoxy/gl.h>
66  * #include <epoxy/glx.h>
67  * ```
68  *
69  * \subsection using_include_sec Headers
70  *
71  * Epoxy comes with the following public headers:
72  *
73  *  - `epoxy/gl.h`  - For GL API
74  *  - `epoxy/egl.h` - For EGL API
75  *  - `epoxy/glx.h` - For GLX API
76  *  - `epoxy/wgl.h` - For WGL API
77  *
78  * \section links_sec Additional links
79  *
80  * The latest version of the Epoxy code is available on [GitHub](https://github.com/anholt/libepoxy).
81  *
82  * For bug reports and enhancements, please use the [Issues](https://github.com/anholt/libepoxy/issues)
83  * link.
84  *
85  * The scope of this API reference does not include the documentation for
86  * OpenGL and OpenGL ES. For more information on those programming interfaces
87  * please visit:
88  *
89  *  - [Khronos](https://www.khronos.org/)
90  *  - [OpenGL page on Khronos.org](https://www.khronos.org/opengl/)
91  *  - [OpenGL ES page on Khronos.org](https://www.khronos.org/opengles/)
92  *  - [docs.GL](http://docs.gl/)
93  */
94 
95 /**
96  * @file dispatch_common.c
97  *
98  * @brief Implements common code shared by the generated GL/EGL/GLX dispatch code.
99  *
100  * A collection of some important specs on getting GL function pointers.
101  *
102  * From the linux GL ABI (http://www.opengl.org/registry/ABI/):
103  *
104  *     "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and
105  *           ARB_multitexture entry points statically.
106  *
107  *      3.5. Because non-ARB extensions vary so widely and are constantly
108  *           increasing in number, it's infeasible to require that they all be
109  *           supported, and extensions can always be added to hardware drivers
110  *           after the base link libraries are released. These drivers are
111  *           dynamically loaded by libGL, so extensions not in the base
112  *           library must also be obtained dynamically.
113  *
114  *      3.6. To perform the dynamic query, libGL also must export an entry
115  *           point called
116  *
117  *           void (*glXGetProcAddressARB(const GLubyte *))();
118  *
119  *      The full specification of this function is available separately. It
120  *      takes the string name of a GL or GLX entry point and returns a pointer
121  *      to a function implementing that entry point. It is functionally
122  *      identical to the wglGetProcAddress query defined by the Windows OpenGL
123  *      library, except that the function pointers returned are context
124  *      independent, unlike the WGL query."
125  *
126  * From the EGL 1.4 spec:
127  *
128  *    "Client API function pointers returned by eglGetProcAddress are
129  *     independent of the display and the currently bound client API context,
130  *     and may be used by any client API context which supports the extension.
131  *
132  *     eglGetProcAddress may be queried for all of the following functions:
133  *
134  *     • All EGL and client API extension functions supported by the
135  *       implementation (whether those extensions are supported by the current
136  *       client API context or not). This includes any mandatory OpenGL ES
137  *       extensions.
138  *
139  *     eglGetProcAddress may not be queried for core (non-extension) functions
140  *     in EGL or client APIs 20 .
141  *
142  *     For functions that are queryable with eglGetProcAddress,
143  *     implementations may choose to also export those functions statically
144  *     from the object libraries im- plementing those functions. However,
145  *     portable clients cannot rely on this behavior.
146  *
147  * From the GLX 1.4 spec:
148  *
149  *     "glXGetProcAddress may be queried for all of the following functions:
150  *
151  *      • All GL and GLX extension functions supported by the implementation
152  *        (whether those extensions are supported by the current context or
153  *        not).
154  *
155  *      • All core (non-extension) functions in GL and GLX from version 1.0 up
156  *        to and including the versions of those specifications supported by
157  *        the implementation, as determined by glGetString(GL VERSION) and
158  *        glXQueryVersion queries."
159  */
160 
161 #include <assert.h>
162 #include <stdlib.h>
163 #ifdef _WIN32
164 #include <windows.h>
165 #else
166 #include <dlfcn.h>
167 #include <err.h>
168 #include <pthread.h>
169 #endif
170 #include <string.h>
171 #include <ctype.h>
172 #include <stdio.h>
173 
174 #include "dispatch_common.h"
175 
176 #if defined(__APPLE__)
177 #define GLX_LIB "/opt/X11/lib/libGL.1.dylib"
178 #define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
179 #define GLES1_LIB "libGLESv1_CM.so"
180 #define GLES2_LIB "libGLESv2.so"
181 #elif defined(__ANDROID__)
182 #define GLX_LIB "libGLESv2.so"
183 #define EGL_LIB "libEGL.so"
184 #define GLES1_LIB "libGLESv1_CM.so"
185 #define GLES2_LIB "libGLESv2.so"
186 #elif defined(_WIN32)
187 #define EGL_LIB "libEGL.dll"
188 #define GLES1_LIB "libGLES_CM.dll"
189 #define GLES2_LIB "libGLESv2.dll"
190 #define OPENGL_LIB "OPENGL32"
191 #else
192 #define GLVND_GLX_LIB "libGLX.so.1"
193 #define GLX_LIB "libGL.so.1"
194 #define EGL_LIB "libEGL.so.1"
195 #define GLES1_LIB "libGLESv1_CM.so.1"
196 #define GLES2_LIB "libGLESv2.so.2"
197 #define OPENGL_LIB "libOpenGL.so.0"
198 #endif
199 
200 #ifdef __GNUC__
201 #define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
202 #define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
203 #elif defined (_MSC_VER) && (_MSC_VER >= 1500)
204 #define CONSTRUCT(_func) \
205   static void _func(void); \
206   static int _func ## _wrapper(void) { _func(); return 0; } \
207   __pragma(section(".CRT$XCU",read)) \
208   __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
209 
210 #define DESTRUCT(_func) \
211   static void _func(void); \
212   static int _func ## _constructor(void) { atexit (_func); return 0; } \
213   __pragma(section(".CRT$XCU",read)) \
214   __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
215 
216 #else
217 #error "You will need constructor support for your compiler"
218 #endif
219 
220 struct api {
221 #ifndef _WIN32
222     /*
223      * Locking for making sure we don't double-dlopen().
224      */
225     pthread_mutex_t mutex;
226 #endif
227 
228     /*
229      * dlopen() return value for the GLX API. This is libGLX.so.1 if the
230      * runtime is glvnd-enabled, else libGL.so.1
231      */
232     void *glx_handle;
233 
234     /*
235      * dlopen() return value for the desktop GL library.
236      *
237      * On Windows this is OPENGL32. On OSX this is classic libGL. On Linux
238      * this is either libOpenGL (if the runtime is glvnd-enabled) or
239      * classic libGL.so.1
240      */
241     void *gl_handle;
242 
243     /* dlopen() return value for libEGL.so.1 */
244     void *egl_handle;
245 
246     /* dlopen() return value for libGLESv1_CM.so.1 */
247     void *gles1_handle;
248 
249     /* dlopen() return value for libGLESv2.so.2 */
250     void *gles2_handle;
251 
252     /*
253      * This value gets incremented when any thread is in
254      * glBegin()/glEnd() called through epoxy.
255      *
256      * We're not guaranteed to be called through our wrapper, so the
257      * conservative paths also try to handle the failure cases they'll
258      * see if begin_count didn't reflect reality.  It's also a bit of
259      * a bug that the conservative paths might return success because
260      * some other thread was in epoxy glBegin/glEnd while our thread
261      * is trying to resolve, but given that it's basically just for
262      * informative error messages, we shouldn't need to care.
263      */
264     long begin_count;
265 };
266 
267 static struct api api = {
268 #ifndef _WIN32
269     .mutex = PTHREAD_MUTEX_INITIALIZER,
270 #else
271 	0,
272 #endif
273 };
274 
275 static bool library_initialized;
276 
277 static bool epoxy_current_context_is_glx(void);
278 
279 #if PLATFORM_HAS_EGL
280 static EGLenum
281 epoxy_egl_get_current_gl_context_api(void);
282 #endif
283 
CONSTRUCT(library_init)284 CONSTRUCT (library_init)
285 
286 static void
287 library_init(void)
288 {
289     library_initialized = true;
290 }
291 
292 static bool
get_dlopen_handle(void ** handle,const char * lib_name,bool exit_on_fail,bool load)293 get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool load)
294 {
295     if (*handle)
296         return true;
297 
298     if (!library_initialized) {
299         fputs("Attempting to dlopen() while in the dynamic linker.\n", stderr);
300         abort();
301     }
302 
303 #ifdef _WIN32
304     *handle = LoadLibraryA(lib_name);
305 #else
306     pthread_mutex_lock(&api.mutex);
307     if (!*handle) {
308         int flags = RTLD_LAZY | RTLD_LOCAL;
309         if (!load)
310             flags |= RTLD_NOLOAD;
311 
312         *handle = dlopen(lib_name, flags);
313         if (!*handle) {
314             if (exit_on_fail) {
315                 fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
316                 abort();
317             } else {
318                 (void)dlerror();
319             }
320         }
321     }
322     pthread_mutex_unlock(&api.mutex);
323 #endif
324 
325     return *handle != NULL;
326 }
327 
328 static void *
do_dlsym(void ** handle,const char * name,bool exit_on_fail)329 do_dlsym(void **handle, const char *name, bool exit_on_fail)
330 {
331     void *result;
332     const char *error = "";
333 
334 #ifdef _WIN32
335     result = GetProcAddress(*handle, name);
336 #else
337     result = dlsym(*handle, name);
338     if (!result)
339         error = dlerror();
340 #endif
341     if (!result && exit_on_fail) {
342         fprintf(stderr, "%s() not found: %s\n", name, error);
343         abort();
344     }
345 
346     return result;
347 }
348 
349 /**
350  * @brief Checks whether we're using OpenGL or OpenGL ES
351  *
352  * @return `true` if we're using OpenGL
353  */
354 bool
epoxy_is_desktop_gl(void)355 epoxy_is_desktop_gl(void)
356 {
357     const char *es_prefix = "OpenGL ES";
358     const char *version;
359 
360 #if PLATFORM_HAS_EGL
361     /* PowerVR's OpenGL ES implementation (and perhaps other) don't
362      * comply with the standard, which states that
363      * "glGetString(GL_VERSION)" should return a string starting with
364      * "OpenGL ES". Therefore, to distinguish desktop OpenGL from
365      * OpenGL ES, we must also check the context type through EGL (we
366      * can do that as PowerVR is only usable through EGL).
367      */
368     if (!epoxy_current_context_is_glx()) {
369         switch (epoxy_egl_get_current_gl_context_api()) {
370         case EGL_OPENGL_API:     return true;
371         case EGL_OPENGL_ES_API:  return false;
372         case EGL_NONE:
373         default:  break;
374         }
375     }
376 #endif
377 
378     if (api.begin_count)
379         return true;
380 
381     version = (const char *)glGetString(GL_VERSION);
382 
383     /* If we didn't get a version back, there are only two things that
384      * could have happened: either malloc failure (which basically
385      * doesn't exist), or we were called within a glBegin()/glEnd().
386      * Assume the second, which only exists for desktop GL.
387      */
388     if (!version)
389         return true;
390 
391     return strncmp(es_prefix, version, strlen(es_prefix));
392 }
393 
394 static int
epoxy_internal_gl_version(GLenum version_string,int error_version,int factor)395 epoxy_internal_gl_version(GLenum version_string, int error_version, int factor)
396 {
397     const char *version = (const char *)glGetString(version_string);
398     GLint major, minor;
399     int scanf_count;
400 
401     if (!version)
402         return error_version;
403 
404     /* skip to version number */
405     while (!isdigit(*version) && *version != '\0')
406         version++;
407 
408     /* Interpret version number */
409     scanf_count = sscanf(version, "%i.%i", &major, &minor);
410     if (scanf_count != 2) {
411         fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
412                 version);
413         abort();
414     }
415 
416     return factor * major + minor;
417 }
418 
419 /**
420  * @brief Returns the version of OpenGL we are using
421  *
422  * The version is encoded as:
423  *
424  * ```
425  *
426  *   version = major * 10 + minor
427  *
428  * ```
429  *
430  * So it can be easily used for version comparisons.
431  *
432  * @return The encoded version of OpenGL we are using
433  */
434 int
epoxy_gl_version(void)435 epoxy_gl_version(void)
436 {
437     return epoxy_internal_gl_version(GL_VERSION, 0, 10);
438 }
439 
440 int
epoxy_conservative_gl_version(void)441 epoxy_conservative_gl_version(void)
442 {
443     if (api.begin_count)
444         return 100;
445 
446     return epoxy_internal_gl_version(GL_VERSION, 100, 10);
447 }
448 
449 /**
450  * @brief Returns the version of the GL Shading Language we are using
451  *
452  * The version is encoded as:
453  *
454  * ```
455  *
456  *   version = major * 100 + minor
457  *
458  * ```
459  *
460  * So it can be easily used for version comparisons.
461  *
462  * @return The encoded version of the GL Shading Language we are using
463  */
464 int
epoxy_glsl_version(void)465 epoxy_glsl_version(void)
466 {
467     if (epoxy_gl_version() >= 20 ||
468         epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
469         return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0, 100);
470 
471     return 0;
472 }
473 
474 /**
475  * @brief Checks for the presence of an extension in an OpenGL extension string
476  *
477  * @param extension_list The string containing the list of extensions to check
478  * @param ext The name of the GL extension
479  * @return `true` if the extension is available'
480  *
481  * @note If you are looking to check whether a normal GL, EGL or GLX extension
482  * is supported by the client, this probably isn't the function you want.
483  *
484  * Some parts of the spec for OpenGL and friends will return an OpenGL formatted
485  * extension string that is separate from the usual extension strings for the
486  * spec. This function provides easy parsing of those strings.
487  *
488  * @see epoxy_has_gl_extension()
489  * @see epoxy_has_egl_extension()
490  * @see epoxy_has_glx_extension()
491  */
492 bool
epoxy_extension_in_string(const char * extension_list,const char * ext)493 epoxy_extension_in_string(const char *extension_list, const char *ext)
494 {
495     const char *ptr = extension_list;
496     int len;
497 
498     if (!ext)
499         return false;
500 
501     len = strlen(ext);
502 
503     if (extension_list == NULL || *extension_list == '\0')
504         return false;
505 
506     /* Make sure that don't just find an extension with our name as a prefix. */
507     while (true) {
508         ptr = strstr(ptr, ext);
509         if (!ptr)
510             return false;
511 
512         if (ptr[len] == ' ' || ptr[len] == 0)
513             return true;
514         ptr += len;
515     }
516 }
517 
518 static bool
epoxy_internal_has_gl_extension(const char * ext,bool invalid_op_mode)519 epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
520 {
521     if (epoxy_gl_version() < 30) {
522         const char *exts = (const char *)glGetString(GL_EXTENSIONS);
523         if (!exts)
524             return invalid_op_mode;
525         return epoxy_extension_in_string(exts, ext);
526     } else {
527         int num_extensions;
528         int i;
529 
530         glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
531         if (num_extensions == 0)
532             return invalid_op_mode;
533 
534         for (i = 0; i < num_extensions; i++) {
535             const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
536             if (!gl_ext)
537                 return false;
538             if (strcmp(ext, gl_ext) == 0)
539                 return true;
540         }
541 
542         return false;
543     }
544 }
545 
546 bool
epoxy_load_glx(bool exit_if_fails,bool load)547 epoxy_load_glx(bool exit_if_fails, bool load)
548 {
549 #if PLATFORM_HAS_GLX
550 # ifdef GLVND_GLX_LIB
551     /* prefer the glvnd library if it exists */
552     if (!api.glx_handle)
553 	get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
554 # endif
555     if (!api.glx_handle)
556         get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
557 #endif
558     return api.glx_handle != NULL;
559 }
560 
561 void *
epoxy_conservative_glx_dlsym(const char * name,bool exit_if_fails)562 epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
563 {
564 #if PLATFORM_HAS_GLX
565     if (epoxy_load_glx(exit_if_fails, exit_if_fails))
566         return do_dlsym(&api.glx_handle, name, exit_if_fails);
567 #endif
568     return NULL;
569 }
570 
571 /**
572  * Tests whether the currently bound context is EGL or GLX, trying to
573  * avoid loading libraries unless necessary.
574  */
575 static bool
epoxy_current_context_is_glx(void)576 epoxy_current_context_is_glx(void)
577 {
578 #if !PLATFORM_HAS_GLX
579     return false;
580 #else
581     void *sym;
582 
583     sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
584     if (sym) {
585         if (glXGetCurrentContext())
586             return true;
587     } else {
588         (void)dlerror();
589     }
590 
591 #if PLATFORM_HAS_EGL
592     sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
593     if (sym) {
594         if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
595             return false;
596     } else {
597         (void)dlerror();
598     }
599 #endif /* PLATFORM_HAS_EGL */
600 
601     return false;
602 #endif /* PLATFORM_HAS_GLX */
603 }
604 
605 /**
606  * @brief Returns true if the given GL extension is supported in the current context.
607  *
608  * @param ext The name of the GL extension
609  * @return `true` if the extension is available
610  *
611  * @note that this function can't be called from within `glBegin()` and `glEnd()`.
612  *
613  * @see epoxy_has_egl_extension()
614  * @see epoxy_has_glx_extension()
615  */
616 bool
epoxy_has_gl_extension(const char * ext)617 epoxy_has_gl_extension(const char *ext)
618 {
619     return epoxy_internal_has_gl_extension(ext, false);
620 }
621 
622 bool
epoxy_conservative_has_gl_extension(const char * ext)623 epoxy_conservative_has_gl_extension(const char *ext)
624 {
625     if (api.begin_count)
626         return true;
627 
628     return epoxy_internal_has_gl_extension(ext, true);
629 }
630 
631 bool
epoxy_load_egl(bool exit_if_fails,bool load)632 epoxy_load_egl(bool exit_if_fails, bool load)
633 {
634 #if PLATFORM_HAS_EGL
635     return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
636 #else
637     return false;
638 #endif
639 }
640 
641 void *
epoxy_conservative_egl_dlsym(const char * name,bool exit_if_fails)642 epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
643 {
644 #if PLATFORM_HAS_EGL
645     if (epoxy_load_egl(exit_if_fails, exit_if_fails))
646         return do_dlsym(&api.egl_handle, name, exit_if_fails);
647 #endif
648     return NULL;
649 }
650 
651 void *
epoxy_egl_dlsym(const char * name)652 epoxy_egl_dlsym(const char *name)
653 {
654     return epoxy_conservative_egl_dlsym(name, true);
655 }
656 
657 void *
epoxy_glx_dlsym(const char * name)658 epoxy_glx_dlsym(const char *name)
659 {
660     return epoxy_conservative_glx_dlsym(name, true);
661 }
662 
663 static void
epoxy_load_gl(void)664 epoxy_load_gl(void)
665 {
666     if (api.gl_handle)
667 	return;
668 
669 #if defined(_WIN32) || defined(__APPLE__)
670     get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
671 #else
672 
673     // Prefer GLX_LIB over OPENGL_LIB to maintain existing behavior.
674     // Using the inverse ordering OPENGL_LIB -> GLX_LIB, causes issues such as:
675     // https://github.com/anholt/libepoxy/issues/240 (apitrace missing calls)
676     // https://github.com/anholt/libepoxy/issues/252 (Xorg boot crash)
677     get_dlopen_handle(&api.glx_handle, GLX_LIB, false, true);
678     api.gl_handle = api.glx_handle;
679 
680 #if defined(OPENGL_LIB)
681     if (!api.gl_handle)
682         get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
683 #endif
684 
685     if (!api.gl_handle) {
686         fprintf(stderr, "Couldn't open %s or %s\n", GLX_LIB, OPENGL_LIB);
687         abort();
688     }
689 
690 #endif
691 }
692 
693 void *
epoxy_gl_dlsym(const char * name)694 epoxy_gl_dlsym(const char *name)
695 {
696     epoxy_load_gl();
697 
698     return do_dlsym(&api.gl_handle, name, true);
699 }
700 
701 void *
epoxy_gles1_dlsym(const char * name)702 epoxy_gles1_dlsym(const char *name)
703 {
704     if (epoxy_current_context_is_glx()) {
705         return epoxy_get_proc_address(name);
706     } else {
707         get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
708         return do_dlsym(&api.gles1_handle, name, true);
709     }
710 }
711 
712 void *
epoxy_gles2_dlsym(const char * name)713 epoxy_gles2_dlsym(const char *name)
714 {
715     if (epoxy_current_context_is_glx()) {
716         return epoxy_get_proc_address(name);
717     } else {
718         get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
719         return do_dlsym(&api.gles2_handle, name, true);
720     }
721 }
722 
723 /**
724  * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
725  * functions.
726  *
727  * Mesa interpreted GLES as intending that the GLES3 functions were
728  * available only through eglGetProcAddress() and not dlsym(), while
729  * ARM's Mali drivers interpreted GLES as intending that GLES3
730  * functions were available only through dlsym() and not
731  * eglGetProcAddress().  Thanks, Khronos.
732  */
733 void *
epoxy_gles3_dlsym(const char * name)734 epoxy_gles3_dlsym(const char *name)
735 {
736     if (epoxy_current_context_is_glx()) {
737         return epoxy_get_proc_address(name);
738     } else {
739         if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
740             void *func = do_dlsym(&api.gles2_handle, name, false);
741 
742             if (func)
743                 return func;
744         }
745 
746         return epoxy_get_proc_address(name);
747     }
748 }
749 
750 /**
751  * Performs either the dlsym or glXGetProcAddress()-equivalent for
752  * core functions in desktop GL.
753  */
754 void *
epoxy_get_core_proc_address(const char * name,int core_version)755 epoxy_get_core_proc_address(const char *name, int core_version)
756 {
757 #ifdef _WIN32
758     int core_symbol_support = 11;
759 #elif defined(__ANDROID__)
760     /**
761      * All symbols must be resolved through eglGetProcAddress
762      * on Android
763      */
764     int core_symbol_support = 0;
765 #else
766     int core_symbol_support = 12;
767 #endif
768 
769     if (core_version <= core_symbol_support) {
770         return epoxy_gl_dlsym(name);
771     } else {
772         return epoxy_get_proc_address(name);
773     }
774 }
775 
776 #if PLATFORM_HAS_EGL
777 static EGLenum
epoxy_egl_get_current_gl_context_api(void)778 epoxy_egl_get_current_gl_context_api(void)
779 {
780     EGLint curapi;
781 
782     if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
783 			EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
784 	(void)eglGetError();
785 	return EGL_NONE;
786     }
787 
788     return (EGLenum) curapi;
789 }
790 #endif /* PLATFORM_HAS_EGL */
791 
792 /**
793  * Performs the dlsym() for the core GL 1.0 functions that we use for
794  * determining version and extension support for deciding on dlsym
795  * versus glXGetProcAddress() for all other functions.
796  *
797  * This needs to succeed on implementations without GLX (since
798  * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
799  * at call time we don't know for sure what API they're trying to use
800  * without inspecting contexts ourselves).
801  */
802 void *
epoxy_get_bootstrap_proc_address(const char * name)803 epoxy_get_bootstrap_proc_address(const char *name)
804 {
805     /* If we already have a library that links to libglapi loaded,
806      * use that.
807      */
808 #if PLATFORM_HAS_GLX
809     if (api.glx_handle && glXGetCurrentContext())
810         return epoxy_gl_dlsym(name);
811 #endif
812 
813     /* If epoxy hasn't loaded any API-specific library yet, try to
814      * figure out what API the context is using and use that library,
815      * since future calls will also use that API (this prevents a
816      * non-X11 ES2 context from loading a bunch of X11 junk).
817      */
818 #if PLATFORM_HAS_EGL
819     get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
820     if (api.egl_handle) {
821         int version = 0;
822         switch (epoxy_egl_get_current_gl_context_api()) {
823         case EGL_OPENGL_API:
824             return epoxy_gl_dlsym(name);
825         case EGL_OPENGL_ES_API:
826             if (eglQueryContext(eglGetCurrentDisplay(),
827                                 eglGetCurrentContext(),
828                                 EGL_CONTEXT_CLIENT_VERSION,
829                                 &version)) {
830                 if (version >= 2)
831                     return epoxy_gles2_dlsym(name);
832                 else
833                     return epoxy_gles1_dlsym(name);
834             }
835         }
836     }
837 #endif /* PLATFORM_HAS_EGL */
838 
839     /* Fall back to GLX */
840     return epoxy_gl_dlsym(name);
841 }
842 
843 void *
epoxy_get_proc_address(const char * name)844 epoxy_get_proc_address(const char *name)
845 {
846 #if PLATFORM_HAS_EGL
847     GLenum egl_api = EGL_NONE;
848 
849     if (!epoxy_current_context_is_glx())
850       egl_api = epoxy_egl_get_current_gl_context_api();
851 
852     switch (egl_api) {
853     case EGL_OPENGL_API:
854     case EGL_OPENGL_ES_API:
855         return eglGetProcAddress(name);
856     case EGL_NONE:
857         break;
858     }
859 #endif
860 
861 #if defined(_WIN32)
862     return wglGetProcAddress(name);
863 #elif defined(__APPLE__)
864     return epoxy_gl_dlsym(name);
865 #elif PLATFORM_HAS_GLX
866     if (epoxy_current_context_is_glx())
867         return glXGetProcAddressARB((const GLubyte *)name);
868     assert(0 && "Couldn't find current GLX or EGL context.\n");
869 #endif
870 
871     return NULL;
872 }
873 
874 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glBegin)875 WRAPPER(epoxy_glBegin)(GLenum primtype)
876 {
877 #ifdef _WIN32
878     InterlockedIncrement(&api.begin_count);
879 #else
880     pthread_mutex_lock(&api.mutex);
881     api.begin_count++;
882     pthread_mutex_unlock(&api.mutex);
883 #endif
884 
885     epoxy_glBegin_unwrapped(primtype);
886 }
887 
888 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glEnd)889 WRAPPER(epoxy_glEnd)(void)
890 {
891     epoxy_glEnd_unwrapped();
892 
893 #ifdef _WIN32
894     InterlockedDecrement(&api.begin_count);
895 #else
896     pthread_mutex_lock(&api.mutex);
897     api.begin_count--;
898     pthread_mutex_unlock(&api.mutex);
899 #endif
900 }
901 
902 PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
903 PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
904 
905 epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
906 
907 /**
908  * Sets the function that will be called every time Epoxy fails to
909  * resolve a symbol.
910  *
911  * @param handler The new handler function
912  * @return The previous handler function
913  */
914 epoxy_resolver_failure_handler_t
epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)915 epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
916 {
917 #ifdef _WIN32
918     return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
919 				      handler);
920 #else
921     epoxy_resolver_failure_handler_t old;
922     pthread_mutex_lock(&api.mutex);
923     old = epoxy_resolver_failure_handler;
924     epoxy_resolver_failure_handler = handler;
925     pthread_mutex_unlock(&api.mutex);
926     return old;
927 #endif
928 }
929