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)395 epoxy_internal_gl_version(GLenum version_string, int error_version)
396 {
397     const char *version = (const char *)glGetString(version_string);
398     GLint major, minor, factor;
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     if (minor >= 10)
417         factor = 100;
418     else
419         factor = 10;
420 
421     return factor * major + minor;
422 }
423 
424 /**
425  * @brief Returns the version of OpenGL we are using
426  *
427  * The version is encoded as:
428  *
429  * ```
430  *
431  *   version = major * 10 + minor
432  *
433  * ```
434  *
435  * So it can be easily used for version comparisons.
436  *
437  * @return The encoded version of OpenGL we are using
438  */
439 int
epoxy_gl_version(void)440 epoxy_gl_version(void)
441 {
442     return epoxy_internal_gl_version(GL_VERSION, 0);
443 }
444 
445 int
epoxy_conservative_gl_version(void)446 epoxy_conservative_gl_version(void)
447 {
448     if (api.begin_count)
449         return 100;
450 
451     return epoxy_internal_gl_version(GL_VERSION, 100);
452 }
453 
454 /**
455  * @brief Returns the version of the GL Shading Language we are using
456  *
457  * The version is encoded as:
458  *
459  * ```
460  *
461  *   version = major * 100 + minor
462  *
463  * ```
464  *
465  * So it can be easily used for version comparisons.
466  *
467  * @return The encoded version of the GL Shading Language we are using
468  */
469 int
epoxy_glsl_version(void)470 epoxy_glsl_version(void)
471 {
472     if (epoxy_gl_version() >= 20 ||
473         epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
474         return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0);
475 
476     return 0;
477 }
478 
479 /**
480  * @brief Checks for the presence of an extension in an OpenGL extension string
481  *
482  * @param extension_list The string containing the list of extensions to check
483  * @param ext The name of the GL extension
484  * @return `true` if the extension is available'
485  *
486  * @note If you are looking to check whether a normal GL, EGL or GLX extension
487  * is supported by the client, this probably isn't the function you want.
488  *
489  * Some parts of the spec for OpenGL and friends will return an OpenGL formatted
490  * extension string that is separate from the usual extension strings for the
491  * spec. This function provides easy parsing of those strings.
492  *
493  * @see epoxy_has_gl_extension()
494  * @see epoxy_has_egl_extension()
495  * @see epoxy_has_glx_extension()
496  */
497 bool
epoxy_extension_in_string(const char * extension_list,const char * ext)498 epoxy_extension_in_string(const char *extension_list, const char *ext)
499 {
500     const char *ptr = extension_list;
501     int len;
502 
503     if (!ext)
504         return false;
505 
506     len = strlen(ext);
507 
508     if (extension_list == NULL || *extension_list == '\0')
509         return false;
510 
511     /* Make sure that don't just find an extension with our name as a prefix. */
512     while (true) {
513         ptr = strstr(ptr, ext);
514         if (!ptr)
515             return false;
516 
517         if (ptr[len] == ' ' || ptr[len] == 0)
518             return true;
519         ptr += len;
520     }
521 }
522 
523 static bool
epoxy_internal_has_gl_extension(const char * ext,bool invalid_op_mode)524 epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
525 {
526     if (epoxy_gl_version() < 30) {
527         const char *exts = (const char *)glGetString(GL_EXTENSIONS);
528         if (!exts)
529             return invalid_op_mode;
530         return epoxy_extension_in_string(exts, ext);
531     } else {
532         int num_extensions;
533         int i;
534 
535         glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
536         if (num_extensions == 0)
537             return invalid_op_mode;
538 
539         for (i = 0; i < num_extensions; i++) {
540             const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
541             if (!gl_ext)
542                 return false;
543             if (strcmp(ext, gl_ext) == 0)
544                 return true;
545         }
546 
547         return false;
548     }
549 }
550 
551 bool
epoxy_load_glx(bool exit_if_fails,bool load)552 epoxy_load_glx(bool exit_if_fails, bool load)
553 {
554 #if PLATFORM_HAS_GLX
555 # ifdef GLVND_GLX_LIB
556     /* prefer the glvnd library if it exists */
557     if (!api.glx_handle)
558 	get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
559 # endif
560     if (!api.glx_handle)
561         get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
562 #endif
563     return api.glx_handle != NULL;
564 }
565 
566 void *
epoxy_conservative_glx_dlsym(const char * name,bool exit_if_fails)567 epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
568 {
569 #if PLATFORM_HAS_GLX
570     if (epoxy_load_glx(exit_if_fails, exit_if_fails))
571         return do_dlsym(&api.glx_handle, name, exit_if_fails);
572 #endif
573     return NULL;
574 }
575 
576 /**
577  * Tests whether the currently bound context is EGL or GLX, trying to
578  * avoid loading libraries unless necessary.
579  */
580 static bool
epoxy_current_context_is_glx(void)581 epoxy_current_context_is_glx(void)
582 {
583 #if !PLATFORM_HAS_GLX
584     return false;
585 #else
586     void *sym;
587 
588     sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
589     if (sym) {
590         if (glXGetCurrentContext())
591             return true;
592     } else {
593         (void)dlerror();
594     }
595 
596 #if PLATFORM_HAS_EGL
597     sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
598     if (sym) {
599         if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
600             return false;
601     } else {
602         (void)dlerror();
603     }
604 #endif /* PLATFORM_HAS_EGL */
605 
606     return false;
607 #endif /* PLATFORM_HAS_GLX */
608 }
609 
610 /**
611  * @brief Returns true if the given GL extension is supported in the current context.
612  *
613  * @param ext The name of the GL extension
614  * @return `true` if the extension is available
615  *
616  * @note that this function can't be called from within `glBegin()` and `glEnd()`.
617  *
618  * @see epoxy_has_egl_extension()
619  * @see epoxy_has_glx_extension()
620  */
621 bool
epoxy_has_gl_extension(const char * ext)622 epoxy_has_gl_extension(const char *ext)
623 {
624     return epoxy_internal_has_gl_extension(ext, false);
625 }
626 
627 bool
epoxy_conservative_has_gl_extension(const char * ext)628 epoxy_conservative_has_gl_extension(const char *ext)
629 {
630     if (api.begin_count)
631         return true;
632 
633     return epoxy_internal_has_gl_extension(ext, true);
634 }
635 
636 bool
epoxy_load_egl(bool exit_if_fails,bool load)637 epoxy_load_egl(bool exit_if_fails, bool load)
638 {
639 #if PLATFORM_HAS_EGL
640     return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
641 #else
642     return false;
643 #endif
644 }
645 
646 void *
epoxy_conservative_egl_dlsym(const char * name,bool exit_if_fails)647 epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
648 {
649 #if PLATFORM_HAS_EGL
650     if (epoxy_load_egl(exit_if_fails, exit_if_fails))
651         return do_dlsym(&api.egl_handle, name, exit_if_fails);
652 #endif
653     return NULL;
654 }
655 
656 void *
epoxy_egl_dlsym(const char * name)657 epoxy_egl_dlsym(const char *name)
658 {
659     return epoxy_conservative_egl_dlsym(name, true);
660 }
661 
662 void *
epoxy_glx_dlsym(const char * name)663 epoxy_glx_dlsym(const char *name)
664 {
665     return epoxy_conservative_glx_dlsym(name, true);
666 }
667 
668 static void
epoxy_load_gl(void)669 epoxy_load_gl(void)
670 {
671     if (api.gl_handle)
672 	return;
673 
674 #if defined(_WIN32) || defined(__APPLE__)
675     get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
676 #else
677 
678 #if defined(OPENGL_LIB)
679     if (!api.gl_handle)
680 	get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
681 #endif
682 
683     get_dlopen_handle(&api.glx_handle, GLX_LIB, true, true);
684     api.gl_handle = api.glx_handle;
685 #endif
686 }
687 
688 void *
epoxy_gl_dlsym(const char * name)689 epoxy_gl_dlsym(const char *name)
690 {
691     epoxy_load_gl();
692 
693     return do_dlsym(&api.gl_handle, name, true);
694 }
695 
696 void *
epoxy_gles1_dlsym(const char * name)697 epoxy_gles1_dlsym(const char *name)
698 {
699     if (epoxy_current_context_is_glx()) {
700         return epoxy_get_proc_address(name);
701     } else {
702         get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
703         return do_dlsym(&api.gles1_handle, name, true);
704     }
705 }
706 
707 void *
epoxy_gles2_dlsym(const char * name)708 epoxy_gles2_dlsym(const char *name)
709 {
710     if (epoxy_current_context_is_glx()) {
711         return epoxy_get_proc_address(name);
712     } else {
713         get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
714         return do_dlsym(&api.gles2_handle, name, true);
715     }
716 }
717 
718 /**
719  * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
720  * functions.
721  *
722  * Mesa interpreted GLES as intending that the GLES3 functions were
723  * available only through eglGetProcAddress() and not dlsym(), while
724  * ARM's Mali drivers interpreted GLES as intending that GLES3
725  * functions were available only through dlsym() and not
726  * eglGetProcAddress().  Thanks, Khronos.
727  */
728 void *
epoxy_gles3_dlsym(const char * name)729 epoxy_gles3_dlsym(const char *name)
730 {
731     if (epoxy_current_context_is_glx()) {
732         return epoxy_get_proc_address(name);
733     } else {
734         if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
735             void *func = do_dlsym(&api.gles2_handle, name, false);
736 
737             if (func)
738                 return func;
739         }
740 
741         return epoxy_get_proc_address(name);
742     }
743 }
744 
745 /**
746  * Performs either the dlsym or glXGetProcAddress()-equivalent for
747  * core functions in desktop GL.
748  */
749 void *
epoxy_get_core_proc_address(const char * name,int core_version)750 epoxy_get_core_proc_address(const char *name, int core_version)
751 {
752 #ifdef _WIN32
753     int core_symbol_support = 11;
754 #elif defined(__ANDROID__)
755     /**
756      * All symbols must be resolved through eglGetProcAddress
757      * on Android
758      */
759     int core_symbol_support = 0;
760 #else
761     int core_symbol_support = 12;
762 #endif
763 
764     if (core_version <= core_symbol_support) {
765         return epoxy_gl_dlsym(name);
766     } else {
767         return epoxy_get_proc_address(name);
768     }
769 }
770 
771 #if PLATFORM_HAS_EGL
772 static EGLenum
epoxy_egl_get_current_gl_context_api(void)773 epoxy_egl_get_current_gl_context_api(void)
774 {
775     EGLint curapi;
776 
777     if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
778 			EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
779 	(void)eglGetError();
780 	return EGL_NONE;
781     }
782 
783     return (EGLenum) curapi;
784 }
785 #endif /* PLATFORM_HAS_EGL */
786 
787 /**
788  * Performs the dlsym() for the core GL 1.0 functions that we use for
789  * determining version and extension support for deciding on dlsym
790  * versus glXGetProcAddress() for all other functions.
791  *
792  * This needs to succeed on implementations without GLX (since
793  * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
794  * at call time we don't know for sure what API they're trying to use
795  * without inspecting contexts ourselves).
796  */
797 void *
epoxy_get_bootstrap_proc_address(const char * name)798 epoxy_get_bootstrap_proc_address(const char *name)
799 {
800     /* If we already have a library that links to libglapi loaded,
801      * use that.
802      */
803 #if PLATFORM_HAS_GLX
804     if (api.glx_handle && glXGetCurrentContext())
805         return epoxy_gl_dlsym(name);
806 #endif
807 
808     /* If epoxy hasn't loaded any API-specific library yet, try to
809      * figure out what API the context is using and use that library,
810      * since future calls will also use that API (this prevents a
811      * non-X11 ES2 context from loading a bunch of X11 junk).
812      */
813 #if PLATFORM_HAS_EGL
814     get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
815     if (api.egl_handle) {
816         int version = 0;
817         switch (epoxy_egl_get_current_gl_context_api()) {
818         case EGL_OPENGL_API:
819             return epoxy_gl_dlsym(name);
820         case EGL_OPENGL_ES_API:
821             if (eglQueryContext(eglGetCurrentDisplay(),
822                                 eglGetCurrentContext(),
823                                 EGL_CONTEXT_CLIENT_VERSION,
824                                 &version)) {
825                 if (version >= 2)
826                     return epoxy_gles2_dlsym(name);
827                 else
828                     return epoxy_gles1_dlsym(name);
829             }
830         }
831     }
832 #endif /* PLATFORM_HAS_EGL */
833 
834     /* Fall back to GLX */
835     return epoxy_gl_dlsym(name);
836 }
837 
838 void *
epoxy_get_proc_address(const char * name)839 epoxy_get_proc_address(const char *name)
840 {
841 #if PLATFORM_HAS_EGL
842     GLenum egl_api = EGL_NONE;
843 
844     if (!epoxy_current_context_is_glx())
845       egl_api = epoxy_egl_get_current_gl_context_api();
846 
847     switch (egl_api) {
848     case EGL_OPENGL_API:
849     case EGL_OPENGL_ES_API:
850         return eglGetProcAddress(name);
851     case EGL_NONE:
852         break;
853     }
854 #endif
855 
856 #if defined(_WIN32)
857     return wglGetProcAddress(name);
858 #elif defined(__APPLE__)
859     return epoxy_gl_dlsym(name);
860 #elif PLATFORM_HAS_GLX
861     if (epoxy_current_context_is_glx())
862         return glXGetProcAddressARB((const GLubyte *)name);
863     assert(0 && "Couldn't find current GLX or EGL context.\n");
864 #endif
865 
866     return NULL;
867 }
868 
869 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glBegin)870 WRAPPER(epoxy_glBegin)(GLenum primtype)
871 {
872 #ifdef _WIN32
873     InterlockedIncrement(&api.begin_count);
874 #else
875     pthread_mutex_lock(&api.mutex);
876     api.begin_count++;
877     pthread_mutex_unlock(&api.mutex);
878 #endif
879 
880     epoxy_glBegin_unwrapped(primtype);
881 }
882 
883 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glEnd)884 WRAPPER(epoxy_glEnd)(void)
885 {
886     epoxy_glEnd_unwrapped();
887 
888 #ifdef _WIN32
889     InterlockedDecrement(&api.begin_count);
890 #else
891     pthread_mutex_lock(&api.mutex);
892     api.begin_count--;
893     pthread_mutex_unlock(&api.mutex);
894 #endif
895 }
896 
897 PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
898 PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
899 
900 epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
901 
902 /**
903  * Sets the function that will be called every time Epoxy fails to
904  * resolve a symbol.
905  *
906  * @param handler The new handler function
907  * @return The previous handler function
908  */
909 epoxy_resolver_failure_handler_t
epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)910 epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
911 {
912 #ifdef _WIN32
913     return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
914 				      handler);
915 #else
916     epoxy_resolver_failure_handler_t old;
917     pthread_mutex_lock(&api.mutex);
918     old = epoxy_resolver_failure_handler;
919     epoxy_resolver_failure_handler = handler;
920     pthread_mutex_unlock(&api.mutex);
921     return old;
922 #endif
923 }
924