dispatch_common.c revision e52adb7b
1e52adb7bSmrg/*
2e52adb7bSmrg * Copyright © 2013-2014 Intel Corporation
3e52adb7bSmrg *
4e52adb7bSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5e52adb7bSmrg * copy of this software and associated documentation files (the "Software"),
6e52adb7bSmrg * to deal in the Software without restriction, including without limitation
7e52adb7bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e52adb7bSmrg * and/or sell copies of the Software, and to permit persons to whom the
9e52adb7bSmrg * Software is furnished to do so, subject to the following conditions:
10e52adb7bSmrg *
11e52adb7bSmrg * The above copyright notice and this permission notice (including the next
12e52adb7bSmrg * paragraph) shall be included in all copies or substantial portions of the
13e52adb7bSmrg * Software.
14e52adb7bSmrg *
15e52adb7bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e52adb7bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e52adb7bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e52adb7bSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e52adb7bSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20e52adb7bSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21e52adb7bSmrg * IN THE SOFTWARE.
22e52adb7bSmrg */
23e52adb7bSmrg
24e52adb7bSmrg/**
25e52adb7bSmrg * @file dispatch_common.c
26e52adb7bSmrg *
27e52adb7bSmrg * Implements common code shared by the generated GL/EGL/GLX dispatch code.
28e52adb7bSmrg *
29e52adb7bSmrg * A collection of some important specs on getting GL function pointers.
30e52adb7bSmrg *
31e52adb7bSmrg * From the linux GL ABI (http://www.opengl.org/registry/ABI/):
32e52adb7bSmrg *
33e52adb7bSmrg *     "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and
34e52adb7bSmrg *           ARB_multitexture entry points statically.
35e52adb7bSmrg *
36e52adb7bSmrg *      3.5. Because non-ARB extensions vary so widely and are constantly
37e52adb7bSmrg *           increasing in number, it's infeasible to require that they all be
38e52adb7bSmrg *           supported, and extensions can always be added to hardware drivers
39e52adb7bSmrg *           after the base link libraries are released. These drivers are
40e52adb7bSmrg *           dynamically loaded by libGL, so extensions not in the base
41e52adb7bSmrg *           library must also be obtained dynamically.
42e52adb7bSmrg *
43e52adb7bSmrg *      3.6. To perform the dynamic query, libGL also must export an entry
44e52adb7bSmrg *           point called
45e52adb7bSmrg *
46e52adb7bSmrg *           void (*glXGetProcAddressARB(const GLubyte *))();
47e52adb7bSmrg *
48e52adb7bSmrg *      The full specification of this function is available separately. It
49e52adb7bSmrg *      takes the string name of a GL or GLX entry point and returns a pointer
50e52adb7bSmrg *      to a function implementing that entry point. It is functionally
51e52adb7bSmrg *      identical to the wglGetProcAddress query defined by the Windows OpenGL
52e52adb7bSmrg *      library, except that the function pointers returned are context
53e52adb7bSmrg *      independent, unlike the WGL query."
54e52adb7bSmrg *
55e52adb7bSmrg * From the EGL 1.4 spec:
56e52adb7bSmrg *
57e52adb7bSmrg *    "Client API function pointers returned by eglGetProcAddress are
58e52adb7bSmrg *     independent of the display and the currently bound client API context,
59e52adb7bSmrg *     and may be used by any client API context which supports the extension.
60e52adb7bSmrg *
61e52adb7bSmrg *     eglGetProcAddress may be queried for all of the following functions:
62e52adb7bSmrg *
63e52adb7bSmrg *     • All EGL and client API extension functions supported by the
64e52adb7bSmrg *       implementation (whether those extensions are supported by the current
65e52adb7bSmrg *       client API context or not). This includes any mandatory OpenGL ES
66e52adb7bSmrg *       extensions.
67e52adb7bSmrg *
68e52adb7bSmrg *     eglGetProcAddress may not be queried for core (non-extension) functions
69e52adb7bSmrg *     in EGL or client APIs 20 .
70e52adb7bSmrg *
71e52adb7bSmrg *     For functions that are queryable with eglGetProcAddress,
72e52adb7bSmrg *     implementations may choose to also export those functions statically
73e52adb7bSmrg *     from the object libraries im- plementing those functions. However,
74e52adb7bSmrg *     portable clients cannot rely on this behavior.
75e52adb7bSmrg *
76e52adb7bSmrg * From the GLX 1.4 spec:
77e52adb7bSmrg *
78e52adb7bSmrg *     "glXGetProcAddress may be queried for all of the following functions:
79e52adb7bSmrg *
80e52adb7bSmrg *      • All GL and GLX extension functions supported by the implementation
81e52adb7bSmrg *        (whether those extensions are supported by the current context or
82e52adb7bSmrg *        not).
83e52adb7bSmrg *
84e52adb7bSmrg *      • All core (non-extension) functions in GL and GLX from version 1.0 up
85e52adb7bSmrg *        to and including the versions of those specifications supported by
86e52adb7bSmrg *        the implementation, as determined by glGetString(GL VERSION) and
87e52adb7bSmrg *        glXQueryVersion queries."
88e52adb7bSmrg */
89e52adb7bSmrg
90e52adb7bSmrg#include <assert.h>
91e52adb7bSmrg#include <stdlib.h>
92e52adb7bSmrg#ifdef _WIN32
93e52adb7bSmrg#include <windows.h>
94e52adb7bSmrg#else
95e52adb7bSmrg#include <dlfcn.h>
96e52adb7bSmrg#include <err.h>
97e52adb7bSmrg#include <pthread.h>
98e52adb7bSmrg#endif
99e52adb7bSmrg#include <string.h>
100e52adb7bSmrg#include <ctype.h>
101e52adb7bSmrg#include <stdio.h>
102e52adb7bSmrg
103e52adb7bSmrg#include "dispatch_common.h"
104e52adb7bSmrg
105e52adb7bSmrg#ifdef __APPLE__
106e52adb7bSmrg#define GLX_LIB "/opt/X11/lib/libGL.1.dylib"
107e52adb7bSmrg#elif defined(ANDROID)
108e52adb7bSmrg#define GLX_LIB "libGLESv2.so"
109e52adb7bSmrg#else
110e52adb7bSmrg#define GLX_LIB "libGL.so.1"
111e52adb7bSmrg#endif
112e52adb7bSmrg
113e52adb7bSmrg#ifdef ANDROID
114e52adb7bSmrg#define EGL_LIB "libEGL.so"
115e52adb7bSmrg#define GLES1_LIB "libGLESv1_CM.so"
116e52adb7bSmrg#define GLES2_LIB "libGLESv2.so"
117e52adb7bSmrg#else
118e52adb7bSmrg#define EGL_LIB "libEGL.so.1"
119e52adb7bSmrg#define GLES1_LIB "libGLESv1_CM.so.1"
120e52adb7bSmrg#define GLES2_LIB "libGLESv2.so.2"
121e52adb7bSmrg#endif
122e52adb7bSmrg
123e52adb7bSmrg#ifdef __GNUC__
124e52adb7bSmrg#define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
125e52adb7bSmrg#define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
126e52adb7bSmrg#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
127e52adb7bSmrg#define CONSTRUCT(_func) \
128e52adb7bSmrg  static void _func(void); \
129e52adb7bSmrg  static int _func ## _wrapper(void) { _func(); return 0; } \
130e52adb7bSmrg  __pragma(section(".CRT$XCU",read)) \
131e52adb7bSmrg  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
132e52adb7bSmrg
133e52adb7bSmrg#define DESTRUCT(_func) \
134e52adb7bSmrg  static void _func(void); \
135e52adb7bSmrg  static int _func ## _constructor(void) { atexit (_func); return 0; } \
136e52adb7bSmrg  __pragma(section(".CRT$XCU",read)) \
137e52adb7bSmrg  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
138e52adb7bSmrg
139e52adb7bSmrg#else
140e52adb7bSmrg#error "You will need constructor support for your compiler"
141e52adb7bSmrg#endif
142e52adb7bSmrg
143e52adb7bSmrgstruct api {
144e52adb7bSmrg#ifndef _WIN32
145e52adb7bSmrg    /**
146e52adb7bSmrg     * Locking for making sure we don't double-dlopen().
147e52adb7bSmrg     */
148e52adb7bSmrg    pthread_mutex_t mutex;
149e52adb7bSmrg#endif
150e52adb7bSmrg
151e52adb7bSmrg    /** dlopen() return value for libGL.so.1. */
152e52adb7bSmrg    void *glx_handle;
153e52adb7bSmrg
154e52adb7bSmrg    /**
155e52adb7bSmrg     * dlopen() return value for OS X's GL library.
156e52adb7bSmrg     *
157e52adb7bSmrg     * On linux, glx_handle is used instead.
158e52adb7bSmrg     */
159e52adb7bSmrg    void *gl_handle;
160e52adb7bSmrg
161e52adb7bSmrg    /** dlopen() return value for libEGL.so.1 */
162e52adb7bSmrg    void *egl_handle;
163e52adb7bSmrg
164e52adb7bSmrg    /** dlopen() return value for libGLESv1_CM.so.1 */
165e52adb7bSmrg    void *gles1_handle;
166e52adb7bSmrg
167e52adb7bSmrg    /** dlopen() return value for libGLESv2.so.2 */
168e52adb7bSmrg    void *gles2_handle;
169e52adb7bSmrg
170e52adb7bSmrg    /**
171e52adb7bSmrg     * This value gets incremented when any thread is in
172e52adb7bSmrg     * glBegin()/glEnd() called through epoxy.
173e52adb7bSmrg     *
174e52adb7bSmrg     * We're not guaranteed to be called through our wrapper, so the
175e52adb7bSmrg     * conservative paths also try to handle the failure cases they'll
176e52adb7bSmrg     * see if begin_count didn't reflect reality.  It's also a bit of
177e52adb7bSmrg     * a bug that the conservative paths might return success because
178e52adb7bSmrg     * some other thread was in epoxy glBegin/glEnd while our thread
179e52adb7bSmrg     * is trying to resolve, but given that it's basically just for
180e52adb7bSmrg     * informative error messages, we shouldn't need to care.
181e52adb7bSmrg     */
182e52adb7bSmrg    long begin_count;
183e52adb7bSmrg};
184e52adb7bSmrg
185e52adb7bSmrgstatic struct api api = {
186e52adb7bSmrg#ifndef _WIN32
187e52adb7bSmrg    .mutex = PTHREAD_MUTEX_INITIALIZER,
188e52adb7bSmrg#else
189e52adb7bSmrg	0,
190e52adb7bSmrg#endif
191e52adb7bSmrg};
192e52adb7bSmrg
193e52adb7bSmrgstatic bool library_initialized;
194e52adb7bSmrg
195e52adb7bSmrgstatic bool epoxy_current_context_is_glx(void);
196e52adb7bSmrg
197e52adb7bSmrg#if PLATFORM_HAS_EGL
198e52adb7bSmrgstatic EGLenum
199e52adb7bSmrgepoxy_egl_get_current_gl_context_api(void);
200e52adb7bSmrg#endif
201e52adb7bSmrg
202e52adb7bSmrgCONSTRUCT (library_init)
203e52adb7bSmrg
204e52adb7bSmrgstatic void
205e52adb7bSmrglibrary_init(void)
206e52adb7bSmrg{
207e52adb7bSmrg    library_initialized = true;
208e52adb7bSmrg}
209e52adb7bSmrg
210e52adb7bSmrgstatic bool
211e52adb7bSmrgget_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail)
212e52adb7bSmrg{
213e52adb7bSmrg    if (*handle)
214e52adb7bSmrg        return true;
215e52adb7bSmrg
216e52adb7bSmrg    if (!library_initialized) {
217e52adb7bSmrg        fprintf(stderr,
218e52adb7bSmrg                "Attempting to dlopen() while in the dynamic linker.\n");
219e52adb7bSmrg        abort();
220e52adb7bSmrg    }
221e52adb7bSmrg
222e52adb7bSmrg#ifdef _WIN32
223e52adb7bSmrg    *handle = LoadLibraryA(lib_name);
224e52adb7bSmrg#else
225e52adb7bSmrg    pthread_mutex_lock(&api.mutex);
226e52adb7bSmrg    if (!*handle) {
227e52adb7bSmrg        *handle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);
228e52adb7bSmrg        if (!*handle) {
229e52adb7bSmrg            if (exit_on_fail) {
230e52adb7bSmrg                fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
231e52adb7bSmrg                exit(1);
232e52adb7bSmrg            } else {
233e52adb7bSmrg                (void)dlerror();
234e52adb7bSmrg            }
235e52adb7bSmrg        }
236e52adb7bSmrg    }
237e52adb7bSmrg    pthread_mutex_unlock(&api.mutex);
238e52adb7bSmrg#endif
239e52adb7bSmrg
240e52adb7bSmrg    return *handle != NULL;
241e52adb7bSmrg}
242e52adb7bSmrg
243e52adb7bSmrgstatic void *
244e52adb7bSmrgdo_dlsym(void **handle, const char *lib_name, const char *name,
245e52adb7bSmrg         bool exit_on_fail)
246e52adb7bSmrg{
247e52adb7bSmrg    void *result;
248e52adb7bSmrg    const char *error = "";
249e52adb7bSmrg
250e52adb7bSmrg    if (!get_dlopen_handle(handle, lib_name, exit_on_fail))
251e52adb7bSmrg        return NULL;
252e52adb7bSmrg
253e52adb7bSmrg#ifdef _WIN32
254e52adb7bSmrg    result = GetProcAddress(*handle, name);
255e52adb7bSmrg#else
256e52adb7bSmrg    result = dlsym(*handle, name);
257e52adb7bSmrg    if (!result)
258e52adb7bSmrg        error = dlerror();
259e52adb7bSmrg#endif
260e52adb7bSmrg    if (!result && exit_on_fail) {
261e52adb7bSmrg        fprintf(stderr,"%s() not found in %s: %s\n", name, lib_name, error);
262e52adb7bSmrg        exit(1);
263e52adb7bSmrg    }
264e52adb7bSmrg
265e52adb7bSmrg    return result;
266e52adb7bSmrg}
267e52adb7bSmrg
268e52adb7bSmrgPUBLIC bool
269e52adb7bSmrgepoxy_is_desktop_gl(void)
270e52adb7bSmrg{
271e52adb7bSmrg    const char *es_prefix = "OpenGL ES";
272e52adb7bSmrg    const char *version;
273e52adb7bSmrg
274e52adb7bSmrg#if PLATFORM_HAS_EGL
275e52adb7bSmrg    /* PowerVR's OpenGL ES implementation (and perhaps other) don't
276e52adb7bSmrg     * comply with the standard, which states that
277e52adb7bSmrg     * "glGetString(GL_VERSION)" should return a string starting with
278e52adb7bSmrg     * "OpenGL ES". Therefore, to distinguish desktop OpenGL from
279e52adb7bSmrg     * OpenGL ES, we must also check the context type through EGL (we
280e52adb7bSmrg     * can do that as PowerVR is only usable through EGL).
281e52adb7bSmrg     */
282e52adb7bSmrg    if (!epoxy_current_context_is_glx()) {
283e52adb7bSmrg        switch (epoxy_egl_get_current_gl_context_api()) {
284e52adb7bSmrg        case EGL_OPENGL_API:     return true;
285e52adb7bSmrg        case EGL_OPENGL_ES_API:  return false;
286e52adb7bSmrg        case EGL_NONE:
287e52adb7bSmrg        default:  break;
288e52adb7bSmrg        }
289e52adb7bSmrg    }
290e52adb7bSmrg#endif
291e52adb7bSmrg
292e52adb7bSmrg    if (api.begin_count)
293e52adb7bSmrg        return true;
294e52adb7bSmrg
295e52adb7bSmrg    version = (const char *)glGetString(GL_VERSION);
296e52adb7bSmrg
297e52adb7bSmrg    /* If we didn't get a version back, there are only two things that
298e52adb7bSmrg     * could have happened: either malloc failure (which basically
299e52adb7bSmrg     * doesn't exist), or we were called within a glBegin()/glEnd().
300e52adb7bSmrg     * Assume the second, which only exists for desktop GL.
301e52adb7bSmrg     */
302e52adb7bSmrg    if (!version)
303e52adb7bSmrg        return true;
304e52adb7bSmrg
305e52adb7bSmrg    return strncmp(es_prefix, version, strlen(es_prefix));
306e52adb7bSmrg}
307e52adb7bSmrg
308e52adb7bSmrgstatic int
309e52adb7bSmrgepoxy_internal_gl_version(int error_version)
310e52adb7bSmrg{
311e52adb7bSmrg    const char *version = (const char *)glGetString(GL_VERSION);
312e52adb7bSmrg    GLint major, minor;
313e52adb7bSmrg    int scanf_count;
314e52adb7bSmrg
315e52adb7bSmrg    if (!version)
316e52adb7bSmrg        return error_version;
317e52adb7bSmrg
318e52adb7bSmrg    /* skip to version number */
319e52adb7bSmrg    while (!isdigit(*version) && *version != '\0')
320e52adb7bSmrg        version++;
321e52adb7bSmrg
322e52adb7bSmrg    /* Interpret version number */
323e52adb7bSmrg    scanf_count = sscanf(version, "%i.%i", &major, &minor);
324e52adb7bSmrg    if (scanf_count != 2) {
325e52adb7bSmrg        fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
326e52adb7bSmrg                version);
327e52adb7bSmrg        exit(1);
328e52adb7bSmrg    }
329e52adb7bSmrg    return 10 * major + minor;
330e52adb7bSmrg}
331e52adb7bSmrg
332e52adb7bSmrgPUBLIC int
333e52adb7bSmrgepoxy_gl_version(void)
334e52adb7bSmrg{
335e52adb7bSmrg    return epoxy_internal_gl_version(0);
336e52adb7bSmrg}
337e52adb7bSmrg
338e52adb7bSmrgint
339e52adb7bSmrgepoxy_conservative_gl_version(void)
340e52adb7bSmrg{
341e52adb7bSmrg    if (api.begin_count)
342e52adb7bSmrg        return 100;
343e52adb7bSmrg
344e52adb7bSmrg    return epoxy_internal_gl_version(100);
345e52adb7bSmrg}
346e52adb7bSmrg
347e52adb7bSmrgbool
348e52adb7bSmrgepoxy_extension_in_string(const char *extension_list, const char *ext)
349e52adb7bSmrg{
350e52adb7bSmrg    const char *ptr = extension_list;
351e52adb7bSmrg    int len = strlen(ext);
352e52adb7bSmrg
353e52adb7bSmrg    /* Make sure that don't just find an extension with our name as a prefix. */
354e52adb7bSmrg    while (true) {
355e52adb7bSmrg        ptr = strstr(ptr, ext);
356e52adb7bSmrg        if (!ptr)
357e52adb7bSmrg            return false;
358e52adb7bSmrg
359e52adb7bSmrg        if (ptr[len] == ' ' || ptr[len] == 0)
360e52adb7bSmrg            return true;
361e52adb7bSmrg        ptr += len;
362e52adb7bSmrg    }
363e52adb7bSmrg}
364e52adb7bSmrg
365e52adb7bSmrgstatic bool
366e52adb7bSmrgepoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
367e52adb7bSmrg{
368e52adb7bSmrg    if (epoxy_gl_version() < 30) {
369e52adb7bSmrg        const char *exts = (const char *)glGetString(GL_EXTENSIONS);
370e52adb7bSmrg        if (!exts)
371e52adb7bSmrg            return invalid_op_mode;
372e52adb7bSmrg        return epoxy_extension_in_string(exts, ext);
373e52adb7bSmrg    } else {
374e52adb7bSmrg        int num_extensions;
375e52adb7bSmrg        int i;
376e52adb7bSmrg
377e52adb7bSmrg        glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
378e52adb7bSmrg        if (num_extensions == 0)
379e52adb7bSmrg            return invalid_op_mode;
380e52adb7bSmrg
381e52adb7bSmrg        for (i = 0; i < num_extensions; i++) {
382e52adb7bSmrg            const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
383e52adb7bSmrg            if (strcmp(ext, gl_ext) == 0)
384e52adb7bSmrg                return true;
385e52adb7bSmrg        }
386e52adb7bSmrg
387e52adb7bSmrg        return false;
388e52adb7bSmrg    }
389e52adb7bSmrg}
390e52adb7bSmrg
391e52adb7bSmrg/**
392e52adb7bSmrg * Tests whether the currently bound context is EGL or GLX, trying to
393e52adb7bSmrg * avoid loading libraries unless necessary.
394e52adb7bSmrg */
395e52adb7bSmrgstatic bool
396e52adb7bSmrgepoxy_current_context_is_glx(void)
397e52adb7bSmrg{
398e52adb7bSmrg#if !PLATFORM_HAS_GLX
399e52adb7bSmrg    return false;
400e52adb7bSmrg#else
401e52adb7bSmrg    /* If the application hasn't explicitly called some of our GLX
402e52adb7bSmrg     * or EGL code but has presumably set up a context on its own,
403e52adb7bSmrg     * then we need to figure out how to getprocaddress anyway.
404e52adb7bSmrg     *
405e52adb7bSmrg     * If there's a public GetProcAddress loaded in the
406e52adb7bSmrg     * application's namespace, then use that.
407e52adb7bSmrg     */
408e52adb7bSmrg    void *sym;
409e52adb7bSmrg
410e52adb7bSmrg    sym = dlsym(NULL, "glXGetCurrentContext");
411e52adb7bSmrg    if (sym) {
412e52adb7bSmrg        if (glXGetCurrentContext())
413e52adb7bSmrg            return true;
414e52adb7bSmrg    } else {
415e52adb7bSmrg        (void)dlerror();
416e52adb7bSmrg    }
417e52adb7bSmrg
418e52adb7bSmrg#if PLATFORM_HAS_EGL
419e52adb7bSmrg    sym = dlsym(NULL, "eglGetCurrentContext");
420e52adb7bSmrg    if (sym) {
421e52adb7bSmrg        if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
422e52adb7bSmrg            return false;
423e52adb7bSmrg    } else {
424e52adb7bSmrg        (void)dlerror();
425e52adb7bSmrg    }
426e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
427e52adb7bSmrg
428e52adb7bSmrg    /* OK, couldn't find anything in the app's address space.
429e52adb7bSmrg     * Presumably they dlopened with RTLD_LOCAL, which hides it
430e52adb7bSmrg     * from us.  Just go dlopen()ing likely libraries and try them.
431e52adb7bSmrg     */
432e52adb7bSmrg    sym = do_dlsym(&api.glx_handle, GLX_LIB, "glXGetCurrentContext", false);
433e52adb7bSmrg    if (sym && glXGetCurrentContext())
434e52adb7bSmrg        return true;
435e52adb7bSmrg
436e52adb7bSmrg#if PLATFORM_HAS_EGL
437e52adb7bSmrg    sym = do_dlsym(&api.egl_handle, EGL_LIB, "eglGetCurrentContext",
438e52adb7bSmrg                   false);
439e52adb7bSmrg    if (sym && epoxy_egl_get_current_gl_context_api() != EGL_NONE)
440e52adb7bSmrg        return false;
441e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
442e52adb7bSmrg
443e52adb7bSmrg    return false;
444e52adb7bSmrg#endif /* PLATFORM_HAS_GLX */
445e52adb7bSmrg}
446e52adb7bSmrg
447e52adb7bSmrg/**
448e52adb7bSmrg * Returns true if the given GL extension is supported in the current context.
449e52adb7bSmrg *
450e52adb7bSmrg * Note that this function can't be called from within glBegin()/glEnd().
451e52adb7bSmrg *
452e52adb7bSmrg * \sa epoxy_has_egl_extension()
453e52adb7bSmrg * \sa epoxy_has_glx_extension()
454e52adb7bSmrg */
455e52adb7bSmrgPUBLIC bool
456e52adb7bSmrgepoxy_has_gl_extension(const char *ext)
457e52adb7bSmrg{
458e52adb7bSmrg    return epoxy_internal_has_gl_extension(ext, false);
459e52adb7bSmrg}
460e52adb7bSmrg
461e52adb7bSmrgbool
462e52adb7bSmrgepoxy_conservative_has_gl_extension(const char *ext)
463e52adb7bSmrg{
464e52adb7bSmrg    if (api.begin_count)
465e52adb7bSmrg        return true;
466e52adb7bSmrg
467e52adb7bSmrg    return epoxy_internal_has_gl_extension(ext, true);
468e52adb7bSmrg}
469e52adb7bSmrg
470e52adb7bSmrgvoid *
471e52adb7bSmrgepoxy_egl_dlsym(const char *name)
472e52adb7bSmrg{
473e52adb7bSmrg    return do_dlsym(&api.egl_handle, EGL_LIB, name, true);
474e52adb7bSmrg}
475e52adb7bSmrg
476e52adb7bSmrgvoid *
477e52adb7bSmrgepoxy_glx_dlsym(const char *name)
478e52adb7bSmrg{
479e52adb7bSmrg    return do_dlsym(&api.glx_handle, GLX_LIB, name, true);
480e52adb7bSmrg}
481e52adb7bSmrg
482e52adb7bSmrgvoid *
483e52adb7bSmrgepoxy_gl_dlsym(const char *name)
484e52adb7bSmrg{
485e52adb7bSmrg#ifdef _WIN32
486e52adb7bSmrg    return do_dlsym(&api.gl_handle, "OPENGL32", name, true);
487e52adb7bSmrg#elif defined(__APPLE__)
488e52adb7bSmrg    return do_dlsym(&api.gl_handle,
489e52adb7bSmrg                    "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL",
490e52adb7bSmrg                    name, true);
491e52adb7bSmrg#else
492e52adb7bSmrg    /* There's no library for desktop GL support independent of GLX. */
493e52adb7bSmrg    return epoxy_glx_dlsym(name);
494e52adb7bSmrg#endif
495e52adb7bSmrg}
496e52adb7bSmrg
497e52adb7bSmrgvoid *
498e52adb7bSmrgepoxy_gles1_dlsym(const char *name)
499e52adb7bSmrg{
500e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
501e52adb7bSmrg        return epoxy_get_proc_address(name);
502e52adb7bSmrg    } else {
503e52adb7bSmrg        return do_dlsym(&api.gles1_handle, GLES1_LIB, name, true);
504e52adb7bSmrg    }
505e52adb7bSmrg}
506e52adb7bSmrg
507e52adb7bSmrgvoid *
508e52adb7bSmrgepoxy_gles2_dlsym(const char *name)
509e52adb7bSmrg{
510e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
511e52adb7bSmrg        return epoxy_get_proc_address(name);
512e52adb7bSmrg    } else {
513e52adb7bSmrg        return do_dlsym(&api.gles2_handle, GLES2_LIB, name, true);
514e52adb7bSmrg    }
515e52adb7bSmrg}
516e52adb7bSmrg
517e52adb7bSmrg/**
518e52adb7bSmrg * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
519e52adb7bSmrg * functions.
520e52adb7bSmrg *
521e52adb7bSmrg * Mesa interpreted GLES as intending that the GLES3 functions were
522e52adb7bSmrg * available only through eglGetProcAddress() and not dlsym(), while
523e52adb7bSmrg * ARM's Mali drivers interpreted GLES as intending that GLES3
524e52adb7bSmrg * functions were available only through dlsym() and not
525e52adb7bSmrg * eglGetProcAddress().  Thanks, Khronos.
526e52adb7bSmrg */
527e52adb7bSmrgvoid *
528e52adb7bSmrgepoxy_gles3_dlsym(const char *name)
529e52adb7bSmrg{
530e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
531e52adb7bSmrg        return epoxy_get_proc_address(name);
532e52adb7bSmrg    } else {
533e52adb7bSmrg        void *func = do_dlsym(&api.gles2_handle, GLES2_LIB, name, false);
534e52adb7bSmrg
535e52adb7bSmrg        if (func)
536e52adb7bSmrg            return func;
537e52adb7bSmrg
538e52adb7bSmrg        return epoxy_get_proc_address(name);
539e52adb7bSmrg    }
540e52adb7bSmrg}
541e52adb7bSmrg
542e52adb7bSmrg/**
543e52adb7bSmrg * Performs either the dlsym or glXGetProcAddress()-equivalent for
544e52adb7bSmrg * core functions in desktop GL.
545e52adb7bSmrg */
546e52adb7bSmrgvoid *
547e52adb7bSmrgepoxy_get_core_proc_address(const char *name, int core_version)
548e52adb7bSmrg{
549e52adb7bSmrg#ifdef _WIN32
550e52adb7bSmrg    int core_symbol_support = 11;
551e52adb7bSmrg#elif defined(ANDROID)
552e52adb7bSmrg    /**
553e52adb7bSmrg     * All symbols must be resolved through eglGetProcAddress
554e52adb7bSmrg     * on Android
555e52adb7bSmrg     */
556e52adb7bSmrg    int core_symbol_support = 0;
557e52adb7bSmrg#else
558e52adb7bSmrg    int core_symbol_support = 12;
559e52adb7bSmrg#endif
560e52adb7bSmrg
561e52adb7bSmrg    if (core_version <= core_symbol_support) {
562e52adb7bSmrg        return epoxy_gl_dlsym(name);
563e52adb7bSmrg    } else {
564e52adb7bSmrg        return epoxy_get_proc_address(name);
565e52adb7bSmrg    }
566e52adb7bSmrg}
567e52adb7bSmrg
568e52adb7bSmrg#if PLATFORM_HAS_EGL
569e52adb7bSmrgstatic EGLenum
570e52adb7bSmrgepoxy_egl_get_current_gl_context_api(void)
571e52adb7bSmrg{
572e52adb7bSmrg    EGLenum save_api = eglQueryAPI();
573e52adb7bSmrg    EGLContext ctx;
574e52adb7bSmrg
575e52adb7bSmrg    if (eglBindAPI(EGL_OPENGL_API)) {
576e52adb7bSmrg        ctx = eglGetCurrentContext();
577e52adb7bSmrg        if (ctx) {
578e52adb7bSmrg            eglBindAPI(save_api);
579e52adb7bSmrg            return EGL_OPENGL_API;
580e52adb7bSmrg        }
581e52adb7bSmrg    } else {
582e52adb7bSmrg        (void)eglGetError();
583e52adb7bSmrg    }
584e52adb7bSmrg
585e52adb7bSmrg    if (eglBindAPI(EGL_OPENGL_ES_API)) {
586e52adb7bSmrg        ctx = eglGetCurrentContext();
587e52adb7bSmrg        eglBindAPI(save_api);
588e52adb7bSmrg        if (ctx) {
589e52adb7bSmrg            eglBindAPI(save_api);
590e52adb7bSmrg            return EGL_OPENGL_ES_API;
591e52adb7bSmrg        }
592e52adb7bSmrg    } else {
593e52adb7bSmrg        (void)eglGetError();
594e52adb7bSmrg    }
595e52adb7bSmrg
596e52adb7bSmrg    return EGL_NONE;
597e52adb7bSmrg}
598e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
599e52adb7bSmrg
600e52adb7bSmrg/**
601e52adb7bSmrg * Performs the dlsym() for the core GL 1.0 functions that we use for
602e52adb7bSmrg * determining version and extension support for deciding on dlsym
603e52adb7bSmrg * versus glXGetProcAddress() for all other functions.
604e52adb7bSmrg *
605e52adb7bSmrg * This needs to succeed on implementations without GLX (since
606e52adb7bSmrg * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
607e52adb7bSmrg * at call time we don't know for sure what API they're trying to use
608e52adb7bSmrg * without inspecting contexts ourselves).
609e52adb7bSmrg */
610e52adb7bSmrgvoid *
611e52adb7bSmrgepoxy_get_bootstrap_proc_address(const char *name)
612e52adb7bSmrg{
613e52adb7bSmrg    /* If we already have a library that links to libglapi loaded,
614e52adb7bSmrg     * use that.
615e52adb7bSmrg     */
616e52adb7bSmrg#if PLATFORM_HAS_GLX
617e52adb7bSmrg    if (api.glx_handle && glXGetCurrentContext())
618e52adb7bSmrg        return epoxy_gl_dlsym(name);
619e52adb7bSmrg#endif
620e52adb7bSmrg
621e52adb7bSmrg    /* If epoxy hasn't loaded any API-specific library yet, try to
622e52adb7bSmrg     * figure out what API the context is using and use that library,
623e52adb7bSmrg     * since future calls will also use that API (this prevents a
624e52adb7bSmrg     * non-X11 ES2 context from loading a bunch of X11 junk).
625e52adb7bSmrg     */
626e52adb7bSmrg#if PLATFORM_HAS_EGL
627e52adb7bSmrg    get_dlopen_handle(&api.egl_handle, EGL_LIB, false);
628e52adb7bSmrg    if (api.egl_handle) {
629e52adb7bSmrg        switch (epoxy_egl_get_current_gl_context_api()) {
630e52adb7bSmrg        case EGL_OPENGL_API:
631e52adb7bSmrg            return epoxy_gl_dlsym(name);
632e52adb7bSmrg        case EGL_OPENGL_ES_API:
633e52adb7bSmrg            /* We can't resolve the GL version, because
634e52adb7bSmrg             * epoxy_glGetString() is one of the two things calling
635e52adb7bSmrg             * us.  Try the GLES2 implementation first, and fall back
636e52adb7bSmrg             * to GLES1 otherwise.
637e52adb7bSmrg             */
638e52adb7bSmrg            get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false);
639e52adb7bSmrg            if (api.gles2_handle)
640e52adb7bSmrg                return epoxy_gles2_dlsym(name);
641e52adb7bSmrg            else
642e52adb7bSmrg                return epoxy_gles1_dlsym(name);
643e52adb7bSmrg        }
644e52adb7bSmrg    }
645e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
646e52adb7bSmrg
647e52adb7bSmrg    /* Fall back to GLX */
648e52adb7bSmrg    return epoxy_gl_dlsym(name);
649e52adb7bSmrg}
650e52adb7bSmrg
651e52adb7bSmrgvoid *
652e52adb7bSmrgepoxy_get_proc_address(const char *name)
653e52adb7bSmrg{
654e52adb7bSmrg#ifdef _WIN32
655e52adb7bSmrg    return wglGetProcAddress(name);
656e52adb7bSmrg#elif defined(__APPLE__)
657e52adb7bSmrg    return epoxy_gl_dlsym(name);
658e52adb7bSmrg#else
659e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
660e52adb7bSmrg        return glXGetProcAddressARB((const GLubyte *)name);
661e52adb7bSmrg    } else {
662e52adb7bSmrg#if PLATFORM_HAS_EGL
663e52adb7bSmrg        GLenum egl_api = epoxy_egl_get_current_gl_context_api();
664e52adb7bSmrg
665e52adb7bSmrg        switch (egl_api) {
666e52adb7bSmrg        case EGL_OPENGL_API:
667e52adb7bSmrg        case EGL_OPENGL_ES_API:
668e52adb7bSmrg            return eglGetProcAddress(name);
669e52adb7bSmrg        case EGL_NONE:
670e52adb7bSmrg            break;
671e52adb7bSmrg        }
672e52adb7bSmrg#endif
673e52adb7bSmrg    }
674e52adb7bSmrg    errx(1, "Couldn't find current GLX or EGL context.\n");
675e52adb7bSmrg#endif
676e52adb7bSmrg}
677e52adb7bSmrg
678e52adb7bSmrgWRAPPER_VISIBILITY (void)
679e52adb7bSmrgWRAPPER(epoxy_glBegin)(GLenum primtype)
680e52adb7bSmrg{
681e52adb7bSmrg#ifdef _WIN32
682e52adb7bSmrg    InterlockedIncrement(&api.begin_count);
683e52adb7bSmrg#else
684e52adb7bSmrg    pthread_mutex_lock(&api.mutex);
685e52adb7bSmrg    api.begin_count++;
686e52adb7bSmrg    pthread_mutex_unlock(&api.mutex);
687e52adb7bSmrg#endif
688e52adb7bSmrg
689e52adb7bSmrg    epoxy_glBegin_unwrapped(primtype);
690e52adb7bSmrg}
691e52adb7bSmrg
692e52adb7bSmrgWRAPPER_VISIBILITY (void)
693e52adb7bSmrgWRAPPER(epoxy_glEnd)(void)
694e52adb7bSmrg{
695e52adb7bSmrg    epoxy_glEnd_unwrapped();
696e52adb7bSmrg
697e52adb7bSmrg#ifdef _WIN32
698e52adb7bSmrg    InterlockedDecrement(&api.begin_count);
699e52adb7bSmrg#else
700e52adb7bSmrg    pthread_mutex_lock(&api.mutex);
701e52adb7bSmrg    api.begin_count--;
702e52adb7bSmrg    pthread_mutex_unlock(&api.mutex);
703e52adb7bSmrg#endif
704e52adb7bSmrg}
705e52adb7bSmrg
706e52adb7bSmrgPUBLIC PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
707e52adb7bSmrgPUBLIC PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
708