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