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

source code of gtk/subprojects/libepoxy/src/dispatch_common.c