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
220 struct 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
267 static struct api api = {
268 #ifndef _WIN32
269 .mutex = PTHREAD_MUTEX_INITIALIZER,
270 #else
271 0,
272 #endif
273 };
274
275 static bool library_initialized;
276
277 static bool epoxy_current_context_is_glx(void);
278
279 #if PLATFORM_HAS_EGL
280 static EGLenum
281 epoxy_egl_get_current_gl_context_api(void);
282 #endif
283
CONSTRUCT(library_init)284 CONSTRUCT (library_init)
285
286 static void
287 library_init(void)
288 {
289 library_initialized = true;
290 }
291
292 static bool
get_dlopen_handle(void ** handle,const char * lib_name,bool exit_on_fail,bool load)293 get_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("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(&api.mutex);
307 if (!*handle) {
308 int flags = RTLD_LAZY | RTLD_LOCAL;
309 if (!load)
310 flags |= RTLD_NOLOAD;
311
312 *handle = dlopen(lib_name, flags);
313 if (!*handle) {
314 if (exit_on_fail) {
315 fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
316 abort();
317 } else {
318 (void)dlerror();
319 }
320 }
321 }
322 pthread_mutex_unlock(&api.mutex);
323 #endif
324
325 return *handle != NULL;
326 }
327
328 static void *
do_dlsym(void ** handle,const char * name,bool exit_on_fail)329 do_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, name);
338 if (!result)
339 error = dlerror();
340 #endif
341 if (!result && exit_on_fail) {
342 fprintf(stderr, "%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 */
354 bool
epoxy_is_desktop_gl(void)355 epoxy_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(es_prefix, version, strlen(es_prefix));
392 }
393
394 static int
epoxy_internal_gl_version(GLenum version_string,int error_version,int factor)395 epoxy_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(version, "%i.%i", &major, &minor);
410 if (scanf_count != 2) {
411 fprintf(stderr, "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 */
434 int
epoxy_gl_version(void)435 epoxy_gl_version(void)
436 {
437 return epoxy_internal_gl_version(GL_VERSION, 0, 10);
438 }
439
440 int
epoxy_conservative_gl_version(void)441 epoxy_conservative_gl_version(void)
442 {
443 if (api.begin_count)
444 return 100;
445
446 return epoxy_internal_gl_version(GL_VERSION, 100, 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 */
464 int
epoxy_glsl_version(void)465 epoxy_glsl_version(void)
466 {
467 if (epoxy_gl_version() >= 20 ||
468 epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
469 return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0, 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 */
492 bool
epoxy_extension_in_string(const char * extension_list,const char * ext)493 epoxy_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(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(ptr, ext);
509 if (!ptr)
510 return false;
511
512 if (ptr[len] == ' ' || ptr[len] == 0)
513 return true;
514 ptr += len;
515 }
516 }
517
518 static bool
epoxy_internal_has_gl_extension(const char * ext,bool invalid_op_mode)519 epoxy_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(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(ext, gl_ext) == 0)
539 return true;
540 }
541
542 return false;
543 }
544 }
545
546 bool
epoxy_load_glx(bool exit_if_fails,bool load)547 epoxy_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(&api.glx_handle, GLVND_GLX_LIB, false, load);
554 # endif
555 if (!api.glx_handle)
556 get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
557 #endif
558 return api.glx_handle != NULL;
559 }
560
561 void *
epoxy_conservative_glx_dlsym(const char * name,bool exit_if_fails)562 epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
563 {
564 #if PLATFORM_HAS_GLX
565 if (epoxy_load_glx(exit_if_fails, exit_if_fails))
566 return do_dlsym(&api.glx_handle, name, 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 */
575 static bool
epoxy_current_context_is_glx(void)576 epoxy_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("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("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 */
616 bool
epoxy_has_gl_extension(const char * ext)617 epoxy_has_gl_extension(const char *ext)
618 {
619 return epoxy_internal_has_gl_extension(ext, false);
620 }
621
622 bool
epoxy_conservative_has_gl_extension(const char * ext)623 epoxy_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
631 bool
epoxy_load_egl(bool exit_if_fails,bool load)632 epoxy_load_egl(bool exit_if_fails, bool load)
633 {
634 #if PLATFORM_HAS_EGL
635 return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
636 #else
637 return false;
638 #endif
639 }
640
641 void *
epoxy_conservative_egl_dlsym(const char * name,bool exit_if_fails)642 epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
643 {
644 #if PLATFORM_HAS_EGL
645 if (epoxy_load_egl(exit_if_fails, exit_if_fails))
646 return do_dlsym(&api.egl_handle, name, exit_if_fails);
647 #endif
648 return NULL;
649 }
650
651 void *
epoxy_egl_dlsym(const char * name)652 epoxy_egl_dlsym(const char *name)
653 {
654 return epoxy_conservative_egl_dlsym(name, true);
655 }
656
657 void *
epoxy_glx_dlsym(const char * name)658 epoxy_glx_dlsym(const char *name)
659 {
660 return epoxy_conservative_glx_dlsym(name, true);
661 }
662
663 static void
epoxy_load_gl(void)664 epoxy_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(&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(&api.gl_handle, OPENGL_LIB, false, true);
683 #endif
684
685 if (!api.gl_handle) {
686 #if defined(OPENGL_LIB)
687 fprintf(stderr, "Couldn't open %s or %s\n", GLX_LIB, OPENGL_LIB);
688 #else
689 fprintf(stderr, "Couldn't open %s\n", GLX_LIB);
690 #endif
691 abort();
692 }
693
694 #endif
695 }
696
697 void *
epoxy_gl_dlsym(const char * name)698 epoxy_gl_dlsym(const char *name)
699 {
700 epoxy_load_gl();
701
702 return do_dlsym(&api.gl_handle, name, true);
703 }
704
705 void *
epoxy_gles1_dlsym(const char * name)706 epoxy_gles1_dlsym(const char *name)
707 {
708 if (epoxy_current_context_is_glx()) {
709 return epoxy_get_proc_address(name);
710 } else {
711 get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
712 return do_dlsym(&api.gles1_handle, name, true);
713 }
714 }
715
716 void *
epoxy_gles2_dlsym(const char * name)717 epoxy_gles2_dlsym(const char *name)
718 {
719 if (epoxy_current_context_is_glx()) {
720 return epoxy_get_proc_address(name);
721 } else {
722 get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
723 return do_dlsym(&api.gles2_handle, name, true);
724 }
725 }
726
727 /**
728 * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
729 * functions.
730 *
731 * Mesa interpreted GLES as intending that the GLES3 functions were
732 * available only through eglGetProcAddress() and not dlsym(), while
733 * ARM's Mali drivers interpreted GLES as intending that GLES3
734 * functions were available only through dlsym() and not
735 * eglGetProcAddress(). Thanks, Khronos.
736 */
737 void *
epoxy_gles3_dlsym(const char * name)738 epoxy_gles3_dlsym(const char *name)
739 {
740 if (epoxy_current_context_is_glx()) {
741 return epoxy_get_proc_address(name);
742 } else {
743 if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
744 void *func = do_dlsym(&api.gles2_handle, name, false);
745
746 if (func)
747 return func;
748 }
749
750 return epoxy_get_proc_address(name);
751 }
752 }
753
754 /**
755 * Performs either the dlsym or glXGetProcAddress()-equivalent for
756 * core functions in desktop GL.
757 */
758 void *
epoxy_get_core_proc_address(const char * name,int core_version)759 epoxy_get_core_proc_address(const char *name, int core_version)
760 {
761 #ifdef _WIN32
762 int core_symbol_support = 11;
763 #elif defined(__ANDROID__)
764 /**
765 * All symbols must be resolved through eglGetProcAddress
766 * on Android
767 */
768 int core_symbol_support = 0;
769 #else
770 int core_symbol_support = 12;
771 #endif
772
773 if (core_version <= core_symbol_support) {
774 return epoxy_gl_dlsym(name);
775 } else {
776 return epoxy_get_proc_address(name);
777 }
778 }
779
780 #if PLATFORM_HAS_EGL
781 static EGLenum
epoxy_egl_get_current_gl_context_api(void)782 epoxy_egl_get_current_gl_context_api(void)
783 {
784 EGLint curapi;
785
786 if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
787 EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
788 (void)eglGetError();
789 return EGL_NONE;
790 }
791
792 return (EGLenum) curapi;
793 }
794 #endif /* PLATFORM_HAS_EGL */
795
796 /**
797 * Performs the dlsym() for the core GL 1.0 functions that we use for
798 * determining version and extension support for deciding on dlsym
799 * versus glXGetProcAddress() for all other functions.
800 *
801 * This needs to succeed on implementations without GLX (since
802 * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
803 * at call time we don't know for sure what API they're trying to use
804 * without inspecting contexts ourselves).
805 */
806 void *
epoxy_get_bootstrap_proc_address(const char * name)807 epoxy_get_bootstrap_proc_address(const char *name)
808 {
809 /* If we already have a library that links to libglapi loaded,
810 * use that.
811 */
812 #if PLATFORM_HAS_GLX
813 if (api.glx_handle && glXGetCurrentContext())
814 return epoxy_gl_dlsym(name);
815 #endif
816
817 /* If epoxy hasn't loaded any API-specific library yet, try to
818 * figure out what API the context is using and use that library,
819 * since future calls will also use that API (this prevents a
820 * non-X11 ES2 context from loading a bunch of X11 junk).
821 */
822 #if PLATFORM_HAS_EGL
823 get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
824 if (api.egl_handle) {
825 int version = 0;
826 switch (epoxy_egl_get_current_gl_context_api()) {
827 case EGL_OPENGL_API:
828 return epoxy_gl_dlsym(name);
829 case EGL_OPENGL_ES_API:
830 if (eglQueryContext(eglGetCurrentDisplay(),
831 eglGetCurrentContext(),
832 EGL_CONTEXT_CLIENT_VERSION,
833 &version)) {
834 if (version >= 2)
835 return epoxy_gles2_dlsym(name);
836 else
837 return epoxy_gles1_dlsym(name);
838 }
839 }
840 }
841 #endif /* PLATFORM_HAS_EGL */
842
843 /* Fall back to GLX */
844 return epoxy_gl_dlsym(name);
845 }
846
847 void *
epoxy_get_proc_address(const char * name)848 epoxy_get_proc_address(const char *name)
849 {
850 #if PLATFORM_HAS_EGL
851 GLenum egl_api = EGL_NONE;
852
853 if (!epoxy_current_context_is_glx())
854 egl_api = epoxy_egl_get_current_gl_context_api();
855
856 switch (egl_api) {
857 case EGL_OPENGL_API:
858 case EGL_OPENGL_ES_API:
859 return eglGetProcAddress(name);
860 case EGL_NONE:
861 break;
862 }
863 #endif
864
865 #if defined(_WIN32)
866 return wglGetProcAddress(name);
867 #elif defined(__APPLE__)
868 return epoxy_gl_dlsym(name);
869 #elif PLATFORM_HAS_GLX
870 if (epoxy_current_context_is_glx())
871 return glXGetProcAddressARB((const GLubyte *)name);
872 assert(0 && "Couldn't find current GLX or EGL context.\n");
873 #endif
874
875 return NULL;
876 }
877
878 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glBegin)879 WRAPPER(epoxy_glBegin)(GLenum primtype)
880 {
881 #ifdef _WIN32
882 InterlockedIncrement(&api.begin_count);
883 #else
884 pthread_mutex_lock(&api.mutex);
885 api.begin_count++;
886 pthread_mutex_unlock(&api.mutex);
887 #endif
888
889 epoxy_glBegin_unwrapped(primtype);
890 }
891
892 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glEnd)893 WRAPPER(epoxy_glEnd)(void)
894 {
895 epoxy_glEnd_unwrapped();
896
897 #ifdef _WIN32
898 InterlockedDecrement(&api.begin_count);
899 #else
900 pthread_mutex_lock(&api.mutex);
901 api.begin_count--;
902 pthread_mutex_unlock(&api.mutex);
903 #endif
904 }
905
906 PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
907 PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
908
909 epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
910
911 /**
912 * Sets the function that will be called every time Epoxy fails to
913 * resolve a symbol.
914 *
915 * @param handler The new handler function
916 * @return The previous handler function
917 */
918 epoxy_resolver_failure_handler_t
epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)919 epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
920 {
921 #ifdef _WIN32
922 return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
923 handler);
924 #else
925 epoxy_resolver_failure_handler_t old;
926 pthread_mutex_lock(&api.mutex);
927 old = epoxy_resolver_failure_handler;
928 epoxy_resolver_failure_handler = handler;
929 pthread_mutex_unlock(&api.mutex);
930 return old;
931 #endif
932 }
933