dispatch_common.c revision 82f995d3
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
110b795ef6aSmrg#ifdef __NetBSD__
111b795ef6aSmrg#define GLX_LIB "libGL.so"
112b795ef6aSmrg#else
113e52adb7bSmrg#define GLX_LIB "libGL.so.1"
114e52adb7bSmrg#endif
115b795ef6aSmrg#endif
116e52adb7bSmrg
117b795ef6aSmrg#if defined(ANDROID) || defined(__NetBSD__)
118e52adb7bSmrg#define EGL_LIB "libEGL.so"
119e52adb7bSmrg#define GLES1_LIB "libGLESv1_CM.so"
120e52adb7bSmrg#define GLES2_LIB "libGLESv2.so"
121e52adb7bSmrg#else
122e52adb7bSmrg#define EGL_LIB "libEGL.so.1"
123e52adb7bSmrg#define GLES1_LIB "libGLESv1_CM.so.1"
124e52adb7bSmrg#define GLES2_LIB "libGLESv2.so.2"
125e52adb7bSmrg#endif
126e52adb7bSmrg
127e52adb7bSmrg#ifdef __GNUC__
128e52adb7bSmrg#define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
129e52adb7bSmrg#define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
130e52adb7bSmrg#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
131e52adb7bSmrg#define CONSTRUCT(_func) \
132e52adb7bSmrg  static void _func(void); \
133e52adb7bSmrg  static int _func ## _wrapper(void) { _func(); return 0; } \
134e52adb7bSmrg  __pragma(section(".CRT$XCU",read)) \
135e52adb7bSmrg  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
136e52adb7bSmrg
137e52adb7bSmrg#define DESTRUCT(_func) \
138e52adb7bSmrg  static void _func(void); \
139e52adb7bSmrg  static int _func ## _constructor(void) { atexit (_func); return 0; } \
140e52adb7bSmrg  __pragma(section(".CRT$XCU",read)) \
141e52adb7bSmrg  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
142e52adb7bSmrg
14382f995d3Schristos#elif defined(__lint__)
14482f995d3Schristos#define CONSTRUCT(_func)
14582f995d3Schristos#define DESTRUCT(_func)
146e52adb7bSmrg#else
147e52adb7bSmrg#error "You will need constructor support for your compiler"
148e52adb7bSmrg#endif
149e52adb7bSmrg
150e52adb7bSmrgstruct api {
151e52adb7bSmrg#ifndef _WIN32
152e52adb7bSmrg    /**
153e52adb7bSmrg     * Locking for making sure we don't double-dlopen().
154e52adb7bSmrg     */
155e52adb7bSmrg    pthread_mutex_t mutex;
156e52adb7bSmrg#endif
157e52adb7bSmrg
158e52adb7bSmrg    /** dlopen() return value for libGL.so.1. */
159e52adb7bSmrg    void *glx_handle;
160e52adb7bSmrg
161e52adb7bSmrg    /**
162e52adb7bSmrg     * dlopen() return value for OS X's GL library.
163e52adb7bSmrg     *
164e52adb7bSmrg     * On linux, glx_handle is used instead.
165e52adb7bSmrg     */
166e52adb7bSmrg    void *gl_handle;
167e52adb7bSmrg
168e52adb7bSmrg    /** dlopen() return value for libEGL.so.1 */
169e52adb7bSmrg    void *egl_handle;
170e52adb7bSmrg
171e52adb7bSmrg    /** dlopen() return value for libGLESv1_CM.so.1 */
172e52adb7bSmrg    void *gles1_handle;
173e52adb7bSmrg
174e52adb7bSmrg    /** dlopen() return value for libGLESv2.so.2 */
175e52adb7bSmrg    void *gles2_handle;
176e52adb7bSmrg
177e52adb7bSmrg    /**
178e52adb7bSmrg     * This value gets incremented when any thread is in
179e52adb7bSmrg     * glBegin()/glEnd() called through epoxy.
180e52adb7bSmrg     *
181e52adb7bSmrg     * We're not guaranteed to be called through our wrapper, so the
182e52adb7bSmrg     * conservative paths also try to handle the failure cases they'll
183e52adb7bSmrg     * see if begin_count didn't reflect reality.  It's also a bit of
184e52adb7bSmrg     * a bug that the conservative paths might return success because
185e52adb7bSmrg     * some other thread was in epoxy glBegin/glEnd while our thread
186e52adb7bSmrg     * is trying to resolve, but given that it's basically just for
187e52adb7bSmrg     * informative error messages, we shouldn't need to care.
188e52adb7bSmrg     */
189e52adb7bSmrg    long begin_count;
190e52adb7bSmrg};
191e52adb7bSmrg
192e52adb7bSmrgstatic struct api api = {
193e52adb7bSmrg#ifndef _WIN32
194e52adb7bSmrg    .mutex = PTHREAD_MUTEX_INITIALIZER,
195e52adb7bSmrg#else
196e52adb7bSmrg	0,
197e52adb7bSmrg#endif
198e52adb7bSmrg};
199e52adb7bSmrg
200e52adb7bSmrgstatic bool library_initialized;
201e52adb7bSmrg
202e52adb7bSmrgstatic bool epoxy_current_context_is_glx(void);
203e52adb7bSmrg
204e52adb7bSmrg#if PLATFORM_HAS_EGL
205e52adb7bSmrgstatic EGLenum
206e52adb7bSmrgepoxy_egl_get_current_gl_context_api(void);
207e52adb7bSmrg#endif
208e52adb7bSmrg
209e52adb7bSmrgCONSTRUCT (library_init)
210e52adb7bSmrg
211e52adb7bSmrgstatic void
212e52adb7bSmrglibrary_init(void)
213e52adb7bSmrg{
214e52adb7bSmrg    library_initialized = true;
215e52adb7bSmrg}
216e52adb7bSmrg
217e52adb7bSmrgstatic bool
218e52adb7bSmrgget_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail)
219e52adb7bSmrg{
220e52adb7bSmrg    if (*handle)
221e52adb7bSmrg        return true;
222e52adb7bSmrg
223e52adb7bSmrg    if (!library_initialized) {
224e52adb7bSmrg        fprintf(stderr,
225e52adb7bSmrg                "Attempting to dlopen() while in the dynamic linker.\n");
226e52adb7bSmrg        abort();
227e52adb7bSmrg    }
228e52adb7bSmrg
229e52adb7bSmrg#ifdef _WIN32
230e52adb7bSmrg    *handle = LoadLibraryA(lib_name);
231e52adb7bSmrg#else
232e52adb7bSmrg    pthread_mutex_lock(&api.mutex);
233e52adb7bSmrg    if (!*handle) {
234e52adb7bSmrg        *handle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);
235e52adb7bSmrg        if (!*handle) {
236e52adb7bSmrg            if (exit_on_fail) {
237e52adb7bSmrg                fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
238e52adb7bSmrg                exit(1);
239e52adb7bSmrg            } else {
240e52adb7bSmrg                (void)dlerror();
241e52adb7bSmrg            }
242e52adb7bSmrg        }
243e52adb7bSmrg    }
244e52adb7bSmrg    pthread_mutex_unlock(&api.mutex);
245e52adb7bSmrg#endif
246e52adb7bSmrg
247e52adb7bSmrg    return *handle != NULL;
248e52adb7bSmrg}
249e52adb7bSmrg
250e52adb7bSmrgstatic void *
251e52adb7bSmrgdo_dlsym(void **handle, const char *lib_name, const char *name,
252e52adb7bSmrg         bool exit_on_fail)
253e52adb7bSmrg{
254e52adb7bSmrg    void *result;
255e52adb7bSmrg    const char *error = "";
256e52adb7bSmrg
257e52adb7bSmrg    if (!get_dlopen_handle(handle, lib_name, exit_on_fail))
258e52adb7bSmrg        return NULL;
259e52adb7bSmrg
260e52adb7bSmrg#ifdef _WIN32
261e52adb7bSmrg    result = GetProcAddress(*handle, name);
262e52adb7bSmrg#else
263e52adb7bSmrg    result = dlsym(*handle, name);
264e52adb7bSmrg    if (!result)
265e52adb7bSmrg        error = dlerror();
266e52adb7bSmrg#endif
267e52adb7bSmrg    if (!result && exit_on_fail) {
268e52adb7bSmrg        fprintf(stderr,"%s() not found in %s: %s\n", name, lib_name, error);
269e52adb7bSmrg        exit(1);
270e52adb7bSmrg    }
271e52adb7bSmrg
272e52adb7bSmrg    return result;
273e52adb7bSmrg}
274e52adb7bSmrg
275e52adb7bSmrgPUBLIC bool
276e52adb7bSmrgepoxy_is_desktop_gl(void)
277e52adb7bSmrg{
278e52adb7bSmrg    const char *es_prefix = "OpenGL ES";
279e52adb7bSmrg    const char *version;
280e52adb7bSmrg
281e52adb7bSmrg#if PLATFORM_HAS_EGL
282e52adb7bSmrg    /* PowerVR's OpenGL ES implementation (and perhaps other) don't
283e52adb7bSmrg     * comply with the standard, which states that
284e52adb7bSmrg     * "glGetString(GL_VERSION)" should return a string starting with
285e52adb7bSmrg     * "OpenGL ES". Therefore, to distinguish desktop OpenGL from
286e52adb7bSmrg     * OpenGL ES, we must also check the context type through EGL (we
287e52adb7bSmrg     * can do that as PowerVR is only usable through EGL).
288e52adb7bSmrg     */
289e52adb7bSmrg    if (!epoxy_current_context_is_glx()) {
290e52adb7bSmrg        switch (epoxy_egl_get_current_gl_context_api()) {
291e52adb7bSmrg        case EGL_OPENGL_API:     return true;
292e52adb7bSmrg        case EGL_OPENGL_ES_API:  return false;
293e52adb7bSmrg        case EGL_NONE:
294e52adb7bSmrg        default:  break;
295e52adb7bSmrg        }
296e52adb7bSmrg    }
297e52adb7bSmrg#endif
298e52adb7bSmrg
299e52adb7bSmrg    if (api.begin_count)
300e52adb7bSmrg        return true;
301e52adb7bSmrg
302e52adb7bSmrg    version = (const char *)glGetString(GL_VERSION);
303e52adb7bSmrg
304e52adb7bSmrg    /* If we didn't get a version back, there are only two things that
305e52adb7bSmrg     * could have happened: either malloc failure (which basically
306e52adb7bSmrg     * doesn't exist), or we were called within a glBegin()/glEnd().
307e52adb7bSmrg     * Assume the second, which only exists for desktop GL.
308e52adb7bSmrg     */
309e52adb7bSmrg    if (!version)
310e52adb7bSmrg        return true;
311e52adb7bSmrg
312e52adb7bSmrg    return strncmp(es_prefix, version, strlen(es_prefix));
313e52adb7bSmrg}
314e52adb7bSmrg
315e52adb7bSmrgstatic int
316e52adb7bSmrgepoxy_internal_gl_version(int error_version)
317e52adb7bSmrg{
318e52adb7bSmrg    const char *version = (const char *)glGetString(GL_VERSION);
319e52adb7bSmrg    GLint major, minor;
320e52adb7bSmrg    int scanf_count;
321e52adb7bSmrg
322e52adb7bSmrg    if (!version)
323e52adb7bSmrg        return error_version;
324e52adb7bSmrg
325e52adb7bSmrg    /* skip to version number */
326e52adb7bSmrg    while (!isdigit(*version) && *version != '\0')
327e52adb7bSmrg        version++;
328e52adb7bSmrg
329e52adb7bSmrg    /* Interpret version number */
330e52adb7bSmrg    scanf_count = sscanf(version, "%i.%i", &major, &minor);
331e52adb7bSmrg    if (scanf_count != 2) {
332e52adb7bSmrg        fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
333e52adb7bSmrg                version);
334e52adb7bSmrg        exit(1);
335e52adb7bSmrg    }
336e52adb7bSmrg    return 10 * major + minor;
337e52adb7bSmrg}
338e52adb7bSmrg
339e52adb7bSmrgPUBLIC int
340e52adb7bSmrgepoxy_gl_version(void)
341e52adb7bSmrg{
342e52adb7bSmrg    return epoxy_internal_gl_version(0);
343e52adb7bSmrg}
344e52adb7bSmrg
345e52adb7bSmrgint
346e52adb7bSmrgepoxy_conservative_gl_version(void)
347e52adb7bSmrg{
348e52adb7bSmrg    if (api.begin_count)
349e52adb7bSmrg        return 100;
350e52adb7bSmrg
351e52adb7bSmrg    return epoxy_internal_gl_version(100);
352e52adb7bSmrg}
353e52adb7bSmrg
354e52adb7bSmrgbool
355e52adb7bSmrgepoxy_extension_in_string(const char *extension_list, const char *ext)
356e52adb7bSmrg{
357e52adb7bSmrg    const char *ptr = extension_list;
358e52adb7bSmrg    int len = strlen(ext);
359e52adb7bSmrg
360e52adb7bSmrg    /* Make sure that don't just find an extension with our name as a prefix. */
361e52adb7bSmrg    while (true) {
362e52adb7bSmrg        ptr = strstr(ptr, ext);
363e52adb7bSmrg        if (!ptr)
364e52adb7bSmrg            return false;
365e52adb7bSmrg
366e52adb7bSmrg        if (ptr[len] == ' ' || ptr[len] == 0)
367e52adb7bSmrg            return true;
368e52adb7bSmrg        ptr += len;
369e52adb7bSmrg    }
370e52adb7bSmrg}
371e52adb7bSmrg
372e52adb7bSmrgstatic bool
373e52adb7bSmrgepoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
374e52adb7bSmrg{
375e52adb7bSmrg    if (epoxy_gl_version() < 30) {
376e52adb7bSmrg        const char *exts = (const char *)glGetString(GL_EXTENSIONS);
377e52adb7bSmrg        if (!exts)
378e52adb7bSmrg            return invalid_op_mode;
379e52adb7bSmrg        return epoxy_extension_in_string(exts, ext);
380e52adb7bSmrg    } else {
381e52adb7bSmrg        int num_extensions;
382e52adb7bSmrg        int i;
383e52adb7bSmrg
384e52adb7bSmrg        glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
385e52adb7bSmrg        if (num_extensions == 0)
386e52adb7bSmrg            return invalid_op_mode;
387e52adb7bSmrg
388e52adb7bSmrg        for (i = 0; i < num_extensions; i++) {
389e52adb7bSmrg            const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
390e52adb7bSmrg            if (strcmp(ext, gl_ext) == 0)
391e52adb7bSmrg                return true;
392e52adb7bSmrg        }
393e52adb7bSmrg
394e52adb7bSmrg        return false;
395e52adb7bSmrg    }
396e52adb7bSmrg}
397e52adb7bSmrg
398e52adb7bSmrg/**
399e52adb7bSmrg * Tests whether the currently bound context is EGL or GLX, trying to
400e52adb7bSmrg * avoid loading libraries unless necessary.
401e52adb7bSmrg */
402e52adb7bSmrgstatic bool
403e52adb7bSmrgepoxy_current_context_is_glx(void)
404e52adb7bSmrg{
405e52adb7bSmrg#if !PLATFORM_HAS_GLX
406e52adb7bSmrg    return false;
407e52adb7bSmrg#else
408e52adb7bSmrg    /* If the application hasn't explicitly called some of our GLX
409e52adb7bSmrg     * or EGL code but has presumably set up a context on its own,
410e52adb7bSmrg     * then we need to figure out how to getprocaddress anyway.
411e52adb7bSmrg     *
412e52adb7bSmrg     * If there's a public GetProcAddress loaded in the
413e52adb7bSmrg     * application's namespace, then use that.
414e52adb7bSmrg     */
415e52adb7bSmrg    void *sym;
416e52adb7bSmrg
417e52adb7bSmrg    sym = dlsym(NULL, "glXGetCurrentContext");
418e52adb7bSmrg    if (sym) {
419e52adb7bSmrg        if (glXGetCurrentContext())
420e52adb7bSmrg            return true;
421e52adb7bSmrg    } else {
422e52adb7bSmrg        (void)dlerror();
423e52adb7bSmrg    }
424e52adb7bSmrg
425e52adb7bSmrg#if PLATFORM_HAS_EGL
426e52adb7bSmrg    sym = dlsym(NULL, "eglGetCurrentContext");
427e52adb7bSmrg    if (sym) {
428e52adb7bSmrg        if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
429e52adb7bSmrg            return false;
430e52adb7bSmrg    } else {
431e52adb7bSmrg        (void)dlerror();
432e52adb7bSmrg    }
433e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
434e52adb7bSmrg
435e52adb7bSmrg    /* OK, couldn't find anything in the app's address space.
436e52adb7bSmrg     * Presumably they dlopened with RTLD_LOCAL, which hides it
437e52adb7bSmrg     * from us.  Just go dlopen()ing likely libraries and try them.
438e52adb7bSmrg     */
439e52adb7bSmrg    sym = do_dlsym(&api.glx_handle, GLX_LIB, "glXGetCurrentContext", false);
440e52adb7bSmrg    if (sym && glXGetCurrentContext())
441e52adb7bSmrg        return true;
442e52adb7bSmrg
443e52adb7bSmrg#if PLATFORM_HAS_EGL
444e52adb7bSmrg    sym = do_dlsym(&api.egl_handle, EGL_LIB, "eglGetCurrentContext",
445e52adb7bSmrg                   false);
446e52adb7bSmrg    if (sym && epoxy_egl_get_current_gl_context_api() != EGL_NONE)
447e52adb7bSmrg        return false;
448e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
449e52adb7bSmrg
450e52adb7bSmrg    return false;
451e52adb7bSmrg#endif /* PLATFORM_HAS_GLX */
452e52adb7bSmrg}
453e52adb7bSmrg
454e52adb7bSmrg/**
455e52adb7bSmrg * Returns true if the given GL extension is supported in the current context.
456e52adb7bSmrg *
457e52adb7bSmrg * Note that this function can't be called from within glBegin()/glEnd().
458e52adb7bSmrg *
459e52adb7bSmrg * \sa epoxy_has_egl_extension()
460e52adb7bSmrg * \sa epoxy_has_glx_extension()
461e52adb7bSmrg */
462e52adb7bSmrgPUBLIC bool
463e52adb7bSmrgepoxy_has_gl_extension(const char *ext)
464e52adb7bSmrg{
465e52adb7bSmrg    return epoxy_internal_has_gl_extension(ext, false);
466e52adb7bSmrg}
467e52adb7bSmrg
468e52adb7bSmrgbool
469e52adb7bSmrgepoxy_conservative_has_gl_extension(const char *ext)
470e52adb7bSmrg{
471e52adb7bSmrg    if (api.begin_count)
472e52adb7bSmrg        return true;
473e52adb7bSmrg
474e52adb7bSmrg    return epoxy_internal_has_gl_extension(ext, true);
475e52adb7bSmrg}
476e52adb7bSmrg
477e52adb7bSmrgvoid *
478e52adb7bSmrgepoxy_egl_dlsym(const char *name)
479e52adb7bSmrg{
480e52adb7bSmrg    return do_dlsym(&api.egl_handle, EGL_LIB, name, true);
481e52adb7bSmrg}
482e52adb7bSmrg
483e52adb7bSmrgvoid *
484e52adb7bSmrgepoxy_glx_dlsym(const char *name)
485e52adb7bSmrg{
486e52adb7bSmrg    return do_dlsym(&api.glx_handle, GLX_LIB, name, true);
487e52adb7bSmrg}
488e52adb7bSmrg
489e52adb7bSmrgvoid *
490e52adb7bSmrgepoxy_gl_dlsym(const char *name)
491e52adb7bSmrg{
492e52adb7bSmrg#ifdef _WIN32
493e52adb7bSmrg    return do_dlsym(&api.gl_handle, "OPENGL32", name, true);
494e52adb7bSmrg#elif defined(__APPLE__)
495e52adb7bSmrg    return do_dlsym(&api.gl_handle,
496e52adb7bSmrg                    "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL",
497e52adb7bSmrg                    name, true);
498e52adb7bSmrg#else
499e52adb7bSmrg    /* There's no library for desktop GL support independent of GLX. */
500e52adb7bSmrg    return epoxy_glx_dlsym(name);
501e52adb7bSmrg#endif
502e52adb7bSmrg}
503e52adb7bSmrg
504e52adb7bSmrgvoid *
505e52adb7bSmrgepoxy_gles1_dlsym(const char *name)
506e52adb7bSmrg{
507e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
508e52adb7bSmrg        return epoxy_get_proc_address(name);
509e52adb7bSmrg    } else {
510e52adb7bSmrg        return do_dlsym(&api.gles1_handle, GLES1_LIB, name, true);
511e52adb7bSmrg    }
512e52adb7bSmrg}
513e52adb7bSmrg
514e52adb7bSmrgvoid *
515e52adb7bSmrgepoxy_gles2_dlsym(const char *name)
516e52adb7bSmrg{
517e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
518e52adb7bSmrg        return epoxy_get_proc_address(name);
519e52adb7bSmrg    } else {
520e52adb7bSmrg        return do_dlsym(&api.gles2_handle, GLES2_LIB, name, true);
521e52adb7bSmrg    }
522e52adb7bSmrg}
523e52adb7bSmrg
524e52adb7bSmrg/**
525e52adb7bSmrg * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
526e52adb7bSmrg * functions.
527e52adb7bSmrg *
528e52adb7bSmrg * Mesa interpreted GLES as intending that the GLES3 functions were
529e52adb7bSmrg * available only through eglGetProcAddress() and not dlsym(), while
530e52adb7bSmrg * ARM's Mali drivers interpreted GLES as intending that GLES3
531e52adb7bSmrg * functions were available only through dlsym() and not
532e52adb7bSmrg * eglGetProcAddress().  Thanks, Khronos.
533e52adb7bSmrg */
534e52adb7bSmrgvoid *
535e52adb7bSmrgepoxy_gles3_dlsym(const char *name)
536e52adb7bSmrg{
537e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
538e52adb7bSmrg        return epoxy_get_proc_address(name);
539e52adb7bSmrg    } else {
540e52adb7bSmrg        void *func = do_dlsym(&api.gles2_handle, GLES2_LIB, name, false);
541e52adb7bSmrg
542e52adb7bSmrg        if (func)
543e52adb7bSmrg            return func;
544e52adb7bSmrg
545e52adb7bSmrg        return epoxy_get_proc_address(name);
546e52adb7bSmrg    }
547e52adb7bSmrg}
548e52adb7bSmrg
549e52adb7bSmrg/**
550e52adb7bSmrg * Performs either the dlsym or glXGetProcAddress()-equivalent for
551e52adb7bSmrg * core functions in desktop GL.
552e52adb7bSmrg */
553e52adb7bSmrgvoid *
554e52adb7bSmrgepoxy_get_core_proc_address(const char *name, int core_version)
555e52adb7bSmrg{
556e52adb7bSmrg#ifdef _WIN32
557e52adb7bSmrg    int core_symbol_support = 11;
558e52adb7bSmrg#elif defined(ANDROID)
559e52adb7bSmrg    /**
560e52adb7bSmrg     * All symbols must be resolved through eglGetProcAddress
561e52adb7bSmrg     * on Android
562e52adb7bSmrg     */
563e52adb7bSmrg    int core_symbol_support = 0;
564e52adb7bSmrg#else
565e52adb7bSmrg    int core_symbol_support = 12;
566e52adb7bSmrg#endif
567e52adb7bSmrg
568e52adb7bSmrg    if (core_version <= core_symbol_support) {
569e52adb7bSmrg        return epoxy_gl_dlsym(name);
570e52adb7bSmrg    } else {
571e52adb7bSmrg        return epoxy_get_proc_address(name);
572e52adb7bSmrg    }
573e52adb7bSmrg}
574e52adb7bSmrg
575e52adb7bSmrg#if PLATFORM_HAS_EGL
576e52adb7bSmrgstatic EGLenum
577e52adb7bSmrgepoxy_egl_get_current_gl_context_api(void)
578e52adb7bSmrg{
579e52adb7bSmrg    EGLenum save_api = eglQueryAPI();
580e52adb7bSmrg    EGLContext ctx;
581e52adb7bSmrg
582e52adb7bSmrg    if (eglBindAPI(EGL_OPENGL_API)) {
583e52adb7bSmrg        ctx = eglGetCurrentContext();
584e52adb7bSmrg        if (ctx) {
585e52adb7bSmrg            eglBindAPI(save_api);
586e52adb7bSmrg            return EGL_OPENGL_API;
587e52adb7bSmrg        }
588e52adb7bSmrg    } else {
589e52adb7bSmrg        (void)eglGetError();
590e52adb7bSmrg    }
591e52adb7bSmrg
592e52adb7bSmrg    if (eglBindAPI(EGL_OPENGL_ES_API)) {
593e52adb7bSmrg        ctx = eglGetCurrentContext();
594e52adb7bSmrg        eglBindAPI(save_api);
595e52adb7bSmrg        if (ctx) {
596e52adb7bSmrg            eglBindAPI(save_api);
597e52adb7bSmrg            return EGL_OPENGL_ES_API;
598e52adb7bSmrg        }
599e52adb7bSmrg    } else {
600e52adb7bSmrg        (void)eglGetError();
601e52adb7bSmrg    }
602e52adb7bSmrg
603e52adb7bSmrg    return EGL_NONE;
604e52adb7bSmrg}
605e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
606e52adb7bSmrg
607e52adb7bSmrg/**
608e52adb7bSmrg * Performs the dlsym() for the core GL 1.0 functions that we use for
609e52adb7bSmrg * determining version and extension support for deciding on dlsym
610e52adb7bSmrg * versus glXGetProcAddress() for all other functions.
611e52adb7bSmrg *
612e52adb7bSmrg * This needs to succeed on implementations without GLX (since
613e52adb7bSmrg * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
614e52adb7bSmrg * at call time we don't know for sure what API they're trying to use
615e52adb7bSmrg * without inspecting contexts ourselves).
616e52adb7bSmrg */
617e52adb7bSmrgvoid *
618e52adb7bSmrgepoxy_get_bootstrap_proc_address(const char *name)
619e52adb7bSmrg{
620e52adb7bSmrg    /* If we already have a library that links to libglapi loaded,
621e52adb7bSmrg     * use that.
622e52adb7bSmrg     */
623e52adb7bSmrg#if PLATFORM_HAS_GLX
624e52adb7bSmrg    if (api.glx_handle && glXGetCurrentContext())
625e52adb7bSmrg        return epoxy_gl_dlsym(name);
626e52adb7bSmrg#endif
627e52adb7bSmrg
628e52adb7bSmrg    /* If epoxy hasn't loaded any API-specific library yet, try to
629e52adb7bSmrg     * figure out what API the context is using and use that library,
630e52adb7bSmrg     * since future calls will also use that API (this prevents a
631e52adb7bSmrg     * non-X11 ES2 context from loading a bunch of X11 junk).
632e52adb7bSmrg     */
633e52adb7bSmrg#if PLATFORM_HAS_EGL
634e52adb7bSmrg    get_dlopen_handle(&api.egl_handle, EGL_LIB, false);
635e52adb7bSmrg    if (api.egl_handle) {
636e52adb7bSmrg        switch (epoxy_egl_get_current_gl_context_api()) {
637e52adb7bSmrg        case EGL_OPENGL_API:
638e52adb7bSmrg            return epoxy_gl_dlsym(name);
639e52adb7bSmrg        case EGL_OPENGL_ES_API:
640e52adb7bSmrg            /* We can't resolve the GL version, because
641e52adb7bSmrg             * epoxy_glGetString() is one of the two things calling
642e52adb7bSmrg             * us.  Try the GLES2 implementation first, and fall back
643e52adb7bSmrg             * to GLES1 otherwise.
644e52adb7bSmrg             */
645e52adb7bSmrg            get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false);
646e52adb7bSmrg            if (api.gles2_handle)
647e52adb7bSmrg                return epoxy_gles2_dlsym(name);
648e52adb7bSmrg            else
649e52adb7bSmrg                return epoxy_gles1_dlsym(name);
650e52adb7bSmrg        }
651e52adb7bSmrg    }
652e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */
653e52adb7bSmrg
654e52adb7bSmrg    /* Fall back to GLX */
655e52adb7bSmrg    return epoxy_gl_dlsym(name);
656e52adb7bSmrg}
657e52adb7bSmrg
658e52adb7bSmrgvoid *
659e52adb7bSmrgepoxy_get_proc_address(const char *name)
660e52adb7bSmrg{
661e52adb7bSmrg#ifdef _WIN32
662e52adb7bSmrg    return wglGetProcAddress(name);
663e52adb7bSmrg#elif defined(__APPLE__)
664e52adb7bSmrg    return epoxy_gl_dlsym(name);
665e52adb7bSmrg#else
666e52adb7bSmrg    if (epoxy_current_context_is_glx()) {
667e52adb7bSmrg        return glXGetProcAddressARB((const GLubyte *)name);
668e52adb7bSmrg    } else {
669e52adb7bSmrg#if PLATFORM_HAS_EGL
670e52adb7bSmrg        GLenum egl_api = epoxy_egl_get_current_gl_context_api();
671e52adb7bSmrg
672e52adb7bSmrg        switch (egl_api) {
673e52adb7bSmrg        case EGL_OPENGL_API:
674e52adb7bSmrg        case EGL_OPENGL_ES_API:
675e52adb7bSmrg            return eglGetProcAddress(name);
676e52adb7bSmrg        case EGL_NONE:
677e52adb7bSmrg            break;
678e52adb7bSmrg        }
679e52adb7bSmrg#endif
680e52adb7bSmrg    }
681e52adb7bSmrg    errx(1, "Couldn't find current GLX or EGL context.\n");
682e52adb7bSmrg#endif
683e52adb7bSmrg}
684e52adb7bSmrg
685e52adb7bSmrgWRAPPER_VISIBILITY (void)
686e52adb7bSmrgWRAPPER(epoxy_glBegin)(GLenum primtype)
687e52adb7bSmrg{
688e52adb7bSmrg#ifdef _WIN32
689e52adb7bSmrg    InterlockedIncrement(&api.begin_count);
690e52adb7bSmrg#else
691e52adb7bSmrg    pthread_mutex_lock(&api.mutex);
692e52adb7bSmrg    api.begin_count++;
693e52adb7bSmrg    pthread_mutex_unlock(&api.mutex);
694e52adb7bSmrg#endif
695e52adb7bSmrg
696e52adb7bSmrg    epoxy_glBegin_unwrapped(primtype);
697e52adb7bSmrg}
698e52adb7bSmrg
699e52adb7bSmrgWRAPPER_VISIBILITY (void)
700e52adb7bSmrgWRAPPER(epoxy_glEnd)(void)
701e52adb7bSmrg{
702e52adb7bSmrg    epoxy_glEnd_unwrapped();
703e52adb7bSmrg
704e52adb7bSmrg#ifdef _WIN32
705e52adb7bSmrg    InterlockedDecrement(&api.begin_count);
706e52adb7bSmrg#else
707e52adb7bSmrg    pthread_mutex_lock(&api.mutex);
708e52adb7bSmrg    api.begin_count--;
709e52adb7bSmrg    pthread_mutex_unlock(&api.mutex);
710e52adb7bSmrg#endif
711e52adb7bSmrg}
712e52adb7bSmrg
713e52adb7bSmrgPUBLIC PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
714e52adb7bSmrgPUBLIC PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
715