Home | History | Annotate | Line # | Download | only in src
      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 #elif __NetBSD__
    184 #define GLX_LIB "libGL.so"
    185 #endif
    186 
    187 #if defined(ANDROID) || defined(__NetBSD__)
    188 #define EGL_LIB "libEGL.so"
    189 #define GLES1_LIB "libGLESv1_CM.so"
    190 #define GLES2_LIB "libGLESv2.so"
    191 #elif defined(_WIN32)
    192 #define EGL_LIB "libEGL.dll"
    193 #define GLES1_LIB "libGLES_CM.dll"
    194 #define GLES2_LIB "libGLESv2.dll"
    195 #define OPENGL_LIB "OPENGL32"
    196 #else
    197 #define GLVND_GLX_LIB "libGLX.so.1"
    198 #define GLX_LIB "libGL.so.1"
    199 #define EGL_LIB "libEGL.so.1"
    200 #define GLES1_LIB "libGLESv1_CM.so.1"
    201 #define GLES2_LIB "libGLESv2.so.2"
    202 #define OPENGL_LIB "libOpenGL.so.0"
    203 #endif
    204 
    205 #ifdef __GNUC__
    206 #define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
    207 #define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
    208 #elif defined (_MSC_VER) && (_MSC_VER >= 1500)
    209 #define CONSTRUCT(_func) \
    210   static void _func(void); \
    211   static int _func ## _wrapper(void) { _func(); return 0; } \
    212   __pragma(section(".CRT$XCU",read)) \
    213   __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
    214 
    215 #define DESTRUCT(_func) \
    216   static void _func(void); \
    217   static int _func ## _constructor(void) { atexit (_func); return 0; } \
    218   __pragma(section(".CRT$XCU",read)) \
    219   __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
    220 
    221 #elif defined(__lint__)
    222 #define CONSTRUCT(_func)
    223 #define DESTRUCT(_func)
    224 #else
    225 #error "You will need constructor support for your compiler"
    226 #endif
    227 
    228 struct api {
    229 #ifndef _WIN32
    230     /*
    231      * Locking for making sure we don't double-dlopen().
    232      */
    233     pthread_mutex_t mutex;
    234 #endif
    235 
    236     /*
    237      * dlopen() return value for the GLX API. This is libGLX.so.1 if the
    238      * runtime is glvnd-enabled, else libGL.so.1
    239      */
    240     void *glx_handle;
    241 
    242     /*
    243      * dlopen() return value for the desktop GL library.
    244      *
    245      * On Windows this is OPENGL32. On OSX this is classic libGL. On Linux
    246      * this is either libOpenGL (if the runtime is glvnd-enabled) or
    247      * classic libGL.so.1
    248      */
    249     void *gl_handle;
    250 
    251     /* dlopen() return value for libEGL.so.1 */
    252     void *egl_handle;
    253 
    254     /* dlopen() return value for libGLESv1_CM.so.1 */
    255     void *gles1_handle;
    256 
    257     /* dlopen() return value for libGLESv2.so.2 */
    258     void *gles2_handle;
    259 
    260     /*
    261      * This value gets incremented when any thread is in
    262      * glBegin()/glEnd() called through epoxy.
    263      *
    264      * We're not guaranteed to be called through our wrapper, so the
    265      * conservative paths also try to handle the failure cases they'll
    266      * see if begin_count didn't reflect reality.  It's also a bit of
    267      * a bug that the conservative paths might return success because
    268      * some other thread was in epoxy glBegin/glEnd while our thread
    269      * is trying to resolve, but given that it's basically just for
    270      * informative error messages, we shouldn't need to care.
    271      */
    272     long begin_count;
    273 };
    274 
    275 static struct api api = {
    276 #ifndef _WIN32
    277     .mutex = PTHREAD_MUTEX_INITIALIZER,
    278 #else
    279 	0,
    280 #endif
    281 };
    282 
    283 static bool library_initialized;
    284 
    285 static bool epoxy_current_context_is_glx(void);
    286 
    287 #if PLATFORM_HAS_EGL
    288 static EGLenum
    289 epoxy_egl_get_current_gl_context_api(void);
    290 #endif
    291 
    292 CONSTRUCT (library_init)
    293 
    294 static void
    295 library_init(void)
    296 {
    297     library_initialized = true;
    298 }
    299 
    300 static bool
    301 get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool load)
    302 {
    303     if (*handle)
    304         return true;
    305 
    306     if (!library_initialized) {
    307         fputs("Attempting to dlopen() while in the dynamic linker.\n", stderr);
    308         abort();
    309     }
    310 
    311 #ifdef _WIN32
    312     *handle = LoadLibraryA(lib_name);
    313 #else
    314     pthread_mutex_lock(&api.mutex);
    315     if (!*handle) {
    316         int flags = RTLD_LAZY | RTLD_LOCAL;
    317         if (!load)
    318             flags |= RTLD_NOLOAD;
    319 
    320         *handle = dlopen(lib_name, flags);
    321         if (!*handle) {
    322             if (exit_on_fail) {
    323                 fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
    324                 abort();
    325             } else {
    326                 (void)dlerror();
    327             }
    328         }
    329     }
    330     pthread_mutex_unlock(&api.mutex);
    331 #endif
    332 
    333     return *handle != NULL;
    334 }
    335 
    336 static void *
    337 do_dlsym(void **handle, const char *name, bool exit_on_fail)
    338 {
    339     void *result;
    340     const char *error = "";
    341 
    342 #ifdef _WIN32
    343     result = GetProcAddress(*handle, name);
    344 #else
    345     result = dlsym(*handle, name);
    346     if (!result)
    347         error = dlerror();
    348 #endif
    349     if (!result && exit_on_fail) {
    350         fprintf(stderr, "%s() not found: %s\n", name, error);
    351         abort();
    352     }
    353 
    354     return result;
    355 }
    356 
    357 /**
    358  * @brief Checks whether we're using OpenGL or OpenGL ES
    359  *
    360  * @return `true` if we're using OpenGL
    361  */
    362 bool
    363 epoxy_is_desktop_gl(void)
    364 {
    365     const char *es_prefix = "OpenGL ES";
    366     const char *version;
    367 
    368 #if PLATFORM_HAS_EGL
    369     /* PowerVR's OpenGL ES implementation (and perhaps other) don't
    370      * comply with the standard, which states that
    371      * "glGetString(GL_VERSION)" should return a string starting with
    372      * "OpenGL ES". Therefore, to distinguish desktop OpenGL from
    373      * OpenGL ES, we must also check the context type through EGL (we
    374      * can do that as PowerVR is only usable through EGL).
    375      */
    376     if (!epoxy_current_context_is_glx()) {
    377         switch (epoxy_egl_get_current_gl_context_api()) {
    378         case EGL_OPENGL_API:     return true;
    379         case EGL_OPENGL_ES_API:  return false;
    380         case EGL_NONE:
    381         default:  break;
    382         }
    383     }
    384 #endif
    385 
    386     if (api.begin_count)
    387         return true;
    388 
    389     version = (const char *)glGetString(GL_VERSION);
    390 
    391     /* If we didn't get a version back, there are only two things that
    392      * could have happened: either malloc failure (which basically
    393      * doesn't exist), or we were called within a glBegin()/glEnd().
    394      * Assume the second, which only exists for desktop GL.
    395      */
    396     if (!version)
    397         return true;
    398 
    399     return strncmp(es_prefix, version, strlen(es_prefix));
    400 }
    401 
    402 static int
    403 epoxy_internal_gl_version(GLenum version_string, int error_version)
    404 {
    405     const char *version = (const char *)glGetString(version_string);
    406     GLint major, minor, factor;
    407     int scanf_count;
    408 
    409     if (!version)
    410         return error_version;
    411 
    412     /* skip to version number */
    413     while (!isdigit(*version) && *version != '\0')
    414         version++;
    415 
    416     /* Interpret version number */
    417     scanf_count = sscanf(version, "%i.%i", &major, &minor);
    418     if (scanf_count != 2) {
    419         fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
    420                 version);
    421         abort();
    422     }
    423 
    424     if (minor >= 10)
    425         factor = 100;
    426     else
    427         factor = 10;
    428 
    429     return factor * major + minor;
    430 }
    431 
    432 /**
    433  * @brief Returns the version of OpenGL we are using
    434  *
    435  * The version is encoded as:
    436  *
    437  * ```
    438  *
    439  *   version = major * 10 + minor
    440  *
    441  * ```
    442  *
    443  * So it can be easily used for version comparisons.
    444  *
    445  * @return The encoded version of OpenGL we are using
    446  */
    447 int
    448 epoxy_gl_version(void)
    449 {
    450     return epoxy_internal_gl_version(GL_VERSION, 0);
    451 }
    452 
    453 int
    454 epoxy_conservative_gl_version(void)
    455 {
    456     if (api.begin_count)
    457         return 100;
    458 
    459     return epoxy_internal_gl_version(GL_VERSION, 100);
    460 }
    461 
    462 /**
    463  * @brief Returns the version of the GL Shading Language we are using
    464  *
    465  * The version is encoded as:
    466  *
    467  * ```
    468  *
    469  *   version = major * 100 + minor
    470  *
    471  * ```
    472  *
    473  * So it can be easily used for version comparisons.
    474  *
    475  * @return The encoded version of the GL Shading Language we are using
    476  */
    477 int
    478 epoxy_glsl_version(void)
    479 {
    480     if (epoxy_gl_version() >= 20 ||
    481         epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
    482         return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0);
    483 
    484     return 0;
    485 }
    486 
    487 /**
    488  * @brief Checks for the presence of an extension in an OpenGL extension string
    489  *
    490  * @param extension_list The string containing the list of extensions to check
    491  * @param ext The name of the GL extension
    492  * @return `true` if the extension is available'
    493  *
    494  * @note If you are looking to check whether a normal GL, EGL or GLX extension
    495  * is supported by the client, this probably isn't the function you want.
    496  *
    497  * Some parts of the spec for OpenGL and friends will return an OpenGL formatted
    498  * extension string that is separate from the usual extension strings for the
    499  * spec. This function provides easy parsing of those strings.
    500  *
    501  * @see epoxy_has_gl_extension()
    502  * @see epoxy_has_egl_extension()
    503  * @see epoxy_has_glx_extension()
    504  */
    505 bool
    506 epoxy_extension_in_string(const char *extension_list, const char *ext)
    507 {
    508     const char *ptr = extension_list;
    509     int len;
    510 
    511     if (!ext)
    512         return false;
    513 
    514     len = strlen(ext);
    515 
    516     if (extension_list == NULL || *extension_list == '\0')
    517         return false;
    518 
    519     /* Make sure that don't just find an extension with our name as a prefix. */
    520     while (true) {
    521         ptr = strstr(ptr, ext);
    522         if (!ptr)
    523             return false;
    524 
    525         if (ptr[len] == ' ' || ptr[len] == 0)
    526             return true;
    527         ptr += len;
    528     }
    529 }
    530 
    531 static bool
    532 epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
    533 {
    534     if (epoxy_gl_version() < 30) {
    535         const char *exts = (const char *)glGetString(GL_EXTENSIONS);
    536         if (!exts)
    537             return invalid_op_mode;
    538         return epoxy_extension_in_string(exts, ext);
    539     } else {
    540         int num_extensions;
    541         int i;
    542 
    543         glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
    544         if (num_extensions == 0)
    545             return invalid_op_mode;
    546 
    547         for (i = 0; i < num_extensions; i++) {
    548             const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
    549             if (!gl_ext)
    550                 return false;
    551             if (strcmp(ext, gl_ext) == 0)
    552                 return true;
    553         }
    554 
    555         return false;
    556     }
    557 }
    558 
    559 bool
    560 epoxy_load_glx(bool exit_if_fails, bool load)
    561 {
    562 #if PLATFORM_HAS_GLX
    563 # ifdef GLVND_GLX_LIB
    564     /* prefer the glvnd library if it exists */
    565     if (!api.glx_handle)
    566 	get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
    567 # endif
    568     if (!api.glx_handle)
    569         get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
    570 #endif
    571     return api.glx_handle != NULL;
    572 }
    573 
    574 void *
    575 epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
    576 {
    577 #if PLATFORM_HAS_GLX
    578     if (epoxy_load_glx(exit_if_fails, exit_if_fails))
    579         return do_dlsym(&api.glx_handle, name, exit_if_fails);
    580 #endif
    581     return NULL;
    582 }
    583 
    584 /**
    585  * Tests whether the currently bound context is EGL or GLX, trying to
    586  * avoid loading libraries unless necessary.
    587  */
    588 static bool
    589 epoxy_current_context_is_glx(void)
    590 {
    591 #if !PLATFORM_HAS_GLX
    592     return false;
    593 #else
    594     void *sym;
    595 
    596     sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
    597     if (sym) {
    598         if (glXGetCurrentContext())
    599             return true;
    600     } else {
    601         (void)dlerror();
    602     }
    603 
    604 #if PLATFORM_HAS_EGL
    605     sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
    606     if (sym) {
    607         if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
    608             return false;
    609     } else {
    610         (void)dlerror();
    611     }
    612 #endif /* PLATFORM_HAS_EGL */
    613 
    614     return false;
    615 #endif /* PLATFORM_HAS_GLX */
    616 }
    617 
    618 /**
    619  * @brief Returns true if the given GL extension is supported in the current context.
    620  *
    621  * @param ext The name of the GL extension
    622  * @return `true` if the extension is available
    623  *
    624  * @note that this function can't be called from within `glBegin()` and `glEnd()`.
    625  *
    626  * @see epoxy_has_egl_extension()
    627  * @see epoxy_has_glx_extension()
    628  */
    629 bool
    630 epoxy_has_gl_extension(const char *ext)
    631 {
    632     return epoxy_internal_has_gl_extension(ext, false);
    633 }
    634 
    635 bool
    636 epoxy_conservative_has_gl_extension(const char *ext)
    637 {
    638     if (api.begin_count)
    639         return true;
    640 
    641     return epoxy_internal_has_gl_extension(ext, true);
    642 }
    643 
    644 bool
    645 epoxy_load_egl(bool exit_if_fails, bool load)
    646 {
    647 #if PLATFORM_HAS_EGL
    648     return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
    649 #else
    650     return false;
    651 #endif
    652 }
    653 
    654 void *
    655 epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
    656 {
    657 #if PLATFORM_HAS_EGL
    658     if (epoxy_load_egl(exit_if_fails, exit_if_fails))
    659         return do_dlsym(&api.egl_handle, name, exit_if_fails);
    660 #endif
    661     return NULL;
    662 }
    663 
    664 void *
    665 epoxy_egl_dlsym(const char *name)
    666 {
    667     return epoxy_conservative_egl_dlsym(name, true);
    668 }
    669 
    670 void *
    671 epoxy_glx_dlsym(const char *name)
    672 {
    673     return epoxy_conservative_glx_dlsym(name, true);
    674 }
    675 
    676 static void
    677 epoxy_load_gl(void)
    678 {
    679     if (api.gl_handle)
    680 	return;
    681 
    682 #if defined(_WIN32) || defined(__APPLE__)
    683     get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
    684 #else
    685 
    686 #if defined(OPENGL_LIB)
    687     if (!api.gl_handle)
    688 	get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
    689 #endif
    690 
    691     get_dlopen_handle(&api.glx_handle, GLX_LIB, true, true);
    692     api.gl_handle = api.glx_handle;
    693 #endif
    694 }
    695 
    696 void *
    697 epoxy_gl_dlsym(const char *name)
    698 {
    699     epoxy_load_gl();
    700 
    701     return do_dlsym(&api.gl_handle, name, true);
    702 }
    703 
    704 void *
    705 epoxy_gles1_dlsym(const char *name)
    706 {
    707     if (epoxy_current_context_is_glx()) {
    708         return epoxy_get_proc_address(name);
    709     } else {
    710         get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
    711         return do_dlsym(&api.gles1_handle, name, true);
    712     }
    713 }
    714 
    715 void *
    716 epoxy_gles2_dlsym(const char *name)
    717 {
    718     if (epoxy_current_context_is_glx()) {
    719         return epoxy_get_proc_address(name);
    720     } else {
    721         get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
    722         return do_dlsym(&api.gles2_handle, name, true);
    723     }
    724 }
    725 
    726 /**
    727  * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
    728  * functions.
    729  *
    730  * Mesa interpreted GLES as intending that the GLES3 functions were
    731  * available only through eglGetProcAddress() and not dlsym(), while
    732  * ARM's Mali drivers interpreted GLES as intending that GLES3
    733  * functions were available only through dlsym() and not
    734  * eglGetProcAddress().  Thanks, Khronos.
    735  */
    736 void *
    737 epoxy_gles3_dlsym(const char *name)
    738 {
    739     if (epoxy_current_context_is_glx()) {
    740         return epoxy_get_proc_address(name);
    741     } else {
    742         if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
    743             void *func = do_dlsym(&api.gles2_handle, name, false);
    744 
    745             if (func)
    746                 return func;
    747         }
    748 
    749         return epoxy_get_proc_address(name);
    750     }
    751 }
    752 
    753 /**
    754  * Performs either the dlsym or glXGetProcAddress()-equivalent for
    755  * core functions in desktop GL.
    756  */
    757 void *
    758 epoxy_get_core_proc_address(const char *name, int core_version)
    759 {
    760 #ifdef _WIN32
    761     int core_symbol_support = 11;
    762 #elif defined(__ANDROID__)
    763     /**
    764      * All symbols must be resolved through eglGetProcAddress
    765      * on Android
    766      */
    767     int core_symbol_support = 0;
    768 #else
    769     int core_symbol_support = 12;
    770 #endif
    771 
    772     if (core_version <= core_symbol_support) {
    773         return epoxy_gl_dlsym(name);
    774     } else {
    775         return epoxy_get_proc_address(name);
    776     }
    777 }
    778 
    779 #if PLATFORM_HAS_EGL
    780 static EGLenum
    781 epoxy_egl_get_current_gl_context_api(void)
    782 {
    783     EGLint curapi;
    784 
    785     if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
    786 			EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
    787 	(void)eglGetError();
    788 	return EGL_NONE;
    789     }
    790 
    791     return (EGLenum) curapi;
    792 }
    793 #endif /* PLATFORM_HAS_EGL */
    794 
    795 /**
    796  * Performs the dlsym() for the core GL 1.0 functions that we use for
    797  * determining version and extension support for deciding on dlsym
    798  * versus glXGetProcAddress() for all other functions.
    799  *
    800  * This needs to succeed on implementations without GLX (since
    801  * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
    802  * at call time we don't know for sure what API they're trying to use
    803  * without inspecting contexts ourselves).
    804  */
    805 void *
    806 epoxy_get_bootstrap_proc_address(const char *name)
    807 {
    808     /* If we already have a library that links to libglapi loaded,
    809      * use that.
    810      */
    811 #if PLATFORM_HAS_GLX
    812     if (api.glx_handle && glXGetCurrentContext())
    813         return epoxy_gl_dlsym(name);
    814 #endif
    815 
    816     /* If epoxy hasn't loaded any API-specific library yet, try to
    817      * figure out what API the context is using and use that library,
    818      * since future calls will also use that API (this prevents a
    819      * non-X11 ES2 context from loading a bunch of X11 junk).
    820      */
    821 #if PLATFORM_HAS_EGL
    822     get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
    823     if (api.egl_handle) {
    824         int version = 0;
    825         switch (epoxy_egl_get_current_gl_context_api()) {
    826         case EGL_OPENGL_API:
    827             return epoxy_gl_dlsym(name);
    828         case EGL_OPENGL_ES_API:
    829             if (eglQueryContext(eglGetCurrentDisplay(),
    830                                 eglGetCurrentContext(),
    831                                 EGL_CONTEXT_CLIENT_VERSION,
    832                                 &version)) {
    833                 if (version >= 2)
    834                     return epoxy_gles2_dlsym(name);
    835                 else
    836                     return epoxy_gles1_dlsym(name);
    837             }
    838         }
    839     }
    840 #endif /* PLATFORM_HAS_EGL */
    841 
    842     /* Fall back to GLX */
    843     return epoxy_gl_dlsym(name);
    844 }
    845 
    846 void *
    847 epoxy_get_proc_address(const char *name)
    848 {
    849 #if PLATFORM_HAS_EGL
    850     GLenum egl_api = EGL_NONE;
    851 
    852     if (!epoxy_current_context_is_glx())
    853       egl_api = epoxy_egl_get_current_gl_context_api();
    854 
    855     switch (egl_api) {
    856     case EGL_OPENGL_API:
    857     case EGL_OPENGL_ES_API:
    858         return eglGetProcAddress(name);
    859     case EGL_NONE:
    860         break;
    861     }
    862 #endif
    863 
    864 #if defined(_WIN32)
    865     return wglGetProcAddress(name);
    866 #elif defined(__APPLE__)
    867     return epoxy_gl_dlsym(name);
    868 #elif PLATFORM_HAS_GLX
    869     if (epoxy_current_context_is_glx())
    870         return glXGetProcAddressARB((const GLubyte *)name);
    871     assert(0 && "Couldn't find current GLX or EGL context.\n");
    872 #endif
    873 
    874     return NULL;
    875 }
    876 
    877 WRAPPER_VISIBILITY (void)
    878 WRAPPER(epoxy_glBegin)(GLenum primtype)
    879 {
    880 #ifdef _WIN32
    881     InterlockedIncrement(&api.begin_count);
    882 #else
    883     pthread_mutex_lock(&api.mutex);
    884     api.begin_count++;
    885     pthread_mutex_unlock(&api.mutex);
    886 #endif
    887 
    888     epoxy_glBegin_unwrapped(primtype);
    889 }
    890 
    891 WRAPPER_VISIBILITY (void)
    892 WRAPPER(epoxy_glEnd)(void)
    893 {
    894     epoxy_glEnd_unwrapped();
    895 
    896 #ifdef _WIN32
    897     InterlockedDecrement(&api.begin_count);
    898 #else
    899     pthread_mutex_lock(&api.mutex);
    900     api.begin_count--;
    901     pthread_mutex_unlock(&api.mutex);
    902 #endif
    903 }
    904 
    905 PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
    906 PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
    907 
    908 epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
    909 
    910 /**
    911  * Sets the function that will be called every time Epoxy fails to
    912  * resolve a symbol.
    913  *
    914  * @param handler The new handler function
    915  * @return The previous handler function
    916  */
    917 epoxy_resolver_failure_handler_t
    918 epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
    919 {
    920 #ifdef _WIN32
    921     return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
    922 				      handler);
    923 #else
    924     epoxy_resolver_failure_handler_t old;
    925     pthread_mutex_lock(&api.mutex);
    926     old = epoxy_resolver_failure_handler;
    927     epoxy_resolver_failure_handler = handler;
    928     pthread_mutex_unlock(&api.mutex);
    929     return old;
    930 #endif
    931 }
    932