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)395 epoxy_internal_gl_version(GLenum version_string, int error_version)
396 {
397 const char *version = (const char *)glGetString(version_string);
398 GLint major, minor, factor;
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 if (minor >= 10)
417 factor = 100;
418 else
419 factor = 10;
420
421 return factor * major + minor;
422 }
423
424 /**
425 * @brief Returns the version of OpenGL we are using
426 *
427 * The version is encoded as:
428 *
429 * ```
430 *
431 * version = major * 10 + minor
432 *
433 * ```
434 *
435 * So it can be easily used for version comparisons.
436 *
437 * @return The encoded version of OpenGL we are using
438 */
439 int
epoxy_gl_version(void)440 epoxy_gl_version(void)
441 {
442 return epoxy_internal_gl_version(GL_VERSION, 0);
443 }
444
445 int
epoxy_conservative_gl_version(void)446 epoxy_conservative_gl_version(void)
447 {
448 if (api.begin_count)
449 return 100;
450
451 return epoxy_internal_gl_version(GL_VERSION, 100);
452 }
453
454 /**
455 * @brief Returns the version of the GL Shading Language we are using
456 *
457 * The version is encoded as:
458 *
459 * ```
460 *
461 * version = major * 100 + minor
462 *
463 * ```
464 *
465 * So it can be easily used for version comparisons.
466 *
467 * @return The encoded version of the GL Shading Language we are using
468 */
469 int
epoxy_glsl_version(void)470 epoxy_glsl_version(void)
471 {
472 if (epoxy_gl_version() >= 20 ||
473 epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
474 return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0);
475
476 return 0;
477 }
478
479 /**
480 * @brief Checks for the presence of an extension in an OpenGL extension string
481 *
482 * @param extension_list The string containing the list of extensions to check
483 * @param ext The name of the GL extension
484 * @return `true` if the extension is available'
485 *
486 * @note If you are looking to check whether a normal GL, EGL or GLX extension
487 * is supported by the client, this probably isn't the function you want.
488 *
489 * Some parts of the spec for OpenGL and friends will return an OpenGL formatted
490 * extension string that is separate from the usual extension strings for the
491 * spec. This function provides easy parsing of those strings.
492 *
493 * @see epoxy_has_gl_extension()
494 * @see epoxy_has_egl_extension()
495 * @see epoxy_has_glx_extension()
496 */
497 bool
epoxy_extension_in_string(const char * extension_list,const char * ext)498 epoxy_extension_in_string(const char *extension_list, const char *ext)
499 {
500 const char *ptr = extension_list;
501 int len;
502
503 if (!ext)
504 return false;
505
506 len = strlen(ext);
507
508 if (extension_list == NULL || *extension_list == '\0')
509 return false;
510
511 /* Make sure that don't just find an extension with our name as a prefix. */
512 while (true) {
513 ptr = strstr(ptr, ext);
514 if (!ptr)
515 return false;
516
517 if (ptr[len] == ' ' || ptr[len] == 0)
518 return true;
519 ptr += len;
520 }
521 }
522
523 static bool
epoxy_internal_has_gl_extension(const char * ext,bool invalid_op_mode)524 epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
525 {
526 if (epoxy_gl_version() < 30) {
527 const char *exts = (const char *)glGetString(GL_EXTENSIONS);
528 if (!exts)
529 return invalid_op_mode;
530 return epoxy_extension_in_string(exts, ext);
531 } else {
532 int num_extensions;
533 int i;
534
535 glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
536 if (num_extensions == 0)
537 return invalid_op_mode;
538
539 for (i = 0; i < num_extensions; i++) {
540 const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
541 if (!gl_ext)
542 return false;
543 if (strcmp(ext, gl_ext) == 0)
544 return true;
545 }
546
547 return false;
548 }
549 }
550
551 bool
epoxy_load_glx(bool exit_if_fails,bool load)552 epoxy_load_glx(bool exit_if_fails, bool load)
553 {
554 #if PLATFORM_HAS_GLX
555 # ifdef GLVND_GLX_LIB
556 /* prefer the glvnd library if it exists */
557 if (!api.glx_handle)
558 get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
559 # endif
560 if (!api.glx_handle)
561 get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
562 #endif
563 return api.glx_handle != NULL;
564 }
565
566 void *
epoxy_conservative_glx_dlsym(const char * name,bool exit_if_fails)567 epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
568 {
569 #if PLATFORM_HAS_GLX
570 if (epoxy_load_glx(exit_if_fails, exit_if_fails))
571 return do_dlsym(&api.glx_handle, name, exit_if_fails);
572 #endif
573 return NULL;
574 }
575
576 /**
577 * Tests whether the currently bound context is EGL or GLX, trying to
578 * avoid loading libraries unless necessary.
579 */
580 static bool
epoxy_current_context_is_glx(void)581 epoxy_current_context_is_glx(void)
582 {
583 #if !PLATFORM_HAS_GLX
584 return false;
585 #else
586 void *sym;
587
588 sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
589 if (sym) {
590 if (glXGetCurrentContext())
591 return true;
592 } else {
593 (void)dlerror();
594 }
595
596 #if PLATFORM_HAS_EGL
597 sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
598 if (sym) {
599 if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
600 return false;
601 } else {
602 (void)dlerror();
603 }
604 #endif /* PLATFORM_HAS_EGL */
605
606 return false;
607 #endif /* PLATFORM_HAS_GLX */
608 }
609
610 /**
611 * @brief Returns true if the given GL extension is supported in the current context.
612 *
613 * @param ext The name of the GL extension
614 * @return `true` if the extension is available
615 *
616 * @note that this function can't be called from within `glBegin()` and `glEnd()`.
617 *
618 * @see epoxy_has_egl_extension()
619 * @see epoxy_has_glx_extension()
620 */
621 bool
epoxy_has_gl_extension(const char * ext)622 epoxy_has_gl_extension(const char *ext)
623 {
624 return epoxy_internal_has_gl_extension(ext, false);
625 }
626
627 bool
epoxy_conservative_has_gl_extension(const char * ext)628 epoxy_conservative_has_gl_extension(const char *ext)
629 {
630 if (api.begin_count)
631 return true;
632
633 return epoxy_internal_has_gl_extension(ext, true);
634 }
635
636 bool
epoxy_load_egl(bool exit_if_fails,bool load)637 epoxy_load_egl(bool exit_if_fails, bool load)
638 {
639 #if PLATFORM_HAS_EGL
640 return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
641 #else
642 return false;
643 #endif
644 }
645
646 void *
epoxy_conservative_egl_dlsym(const char * name,bool exit_if_fails)647 epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
648 {
649 #if PLATFORM_HAS_EGL
650 if (epoxy_load_egl(exit_if_fails, exit_if_fails))
651 return do_dlsym(&api.egl_handle, name, exit_if_fails);
652 #endif
653 return NULL;
654 }
655
656 void *
epoxy_egl_dlsym(const char * name)657 epoxy_egl_dlsym(const char *name)
658 {
659 return epoxy_conservative_egl_dlsym(name, true);
660 }
661
662 void *
epoxy_glx_dlsym(const char * name)663 epoxy_glx_dlsym(const char *name)
664 {
665 return epoxy_conservative_glx_dlsym(name, true);
666 }
667
668 static void
epoxy_load_gl(void)669 epoxy_load_gl(void)
670 {
671 if (api.gl_handle)
672 return;
673
674 #if defined(_WIN32) || defined(__APPLE__)
675 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
676 #else
677
678 #if defined(OPENGL_LIB)
679 if (!api.gl_handle)
680 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
681 #endif
682
683 get_dlopen_handle(&api.glx_handle, GLX_LIB, true, true);
684 api.gl_handle = api.glx_handle;
685 #endif
686 }
687
688 void *
epoxy_gl_dlsym(const char * name)689 epoxy_gl_dlsym(const char *name)
690 {
691 epoxy_load_gl();
692
693 return do_dlsym(&api.gl_handle, name, true);
694 }
695
696 void *
epoxy_gles1_dlsym(const char * name)697 epoxy_gles1_dlsym(const char *name)
698 {
699 if (epoxy_current_context_is_glx()) {
700 return epoxy_get_proc_address(name);
701 } else {
702 get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
703 return do_dlsym(&api.gles1_handle, name, true);
704 }
705 }
706
707 void *
epoxy_gles2_dlsym(const char * name)708 epoxy_gles2_dlsym(const char *name)
709 {
710 if (epoxy_current_context_is_glx()) {
711 return epoxy_get_proc_address(name);
712 } else {
713 get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
714 return do_dlsym(&api.gles2_handle, name, true);
715 }
716 }
717
718 /**
719 * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
720 * functions.
721 *
722 * Mesa interpreted GLES as intending that the GLES3 functions were
723 * available only through eglGetProcAddress() and not dlsym(), while
724 * ARM's Mali drivers interpreted GLES as intending that GLES3
725 * functions were available only through dlsym() and not
726 * eglGetProcAddress(). Thanks, Khronos.
727 */
728 void *
epoxy_gles3_dlsym(const char * name)729 epoxy_gles3_dlsym(const char *name)
730 {
731 if (epoxy_current_context_is_glx()) {
732 return epoxy_get_proc_address(name);
733 } else {
734 if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
735 void *func = do_dlsym(&api.gles2_handle, name, false);
736
737 if (func)
738 return func;
739 }
740
741 return epoxy_get_proc_address(name);
742 }
743 }
744
745 /**
746 * Performs either the dlsym or glXGetProcAddress()-equivalent for
747 * core functions in desktop GL.
748 */
749 void *
epoxy_get_core_proc_address(const char * name,int core_version)750 epoxy_get_core_proc_address(const char *name, int core_version)
751 {
752 #ifdef _WIN32
753 int core_symbol_support = 11;
754 #elif defined(__ANDROID__)
755 /**
756 * All symbols must be resolved through eglGetProcAddress
757 * on Android
758 */
759 int core_symbol_support = 0;
760 #else
761 int core_symbol_support = 12;
762 #endif
763
764 if (core_version <= core_symbol_support) {
765 return epoxy_gl_dlsym(name);
766 } else {
767 return epoxy_get_proc_address(name);
768 }
769 }
770
771 #if PLATFORM_HAS_EGL
772 static EGLenum
epoxy_egl_get_current_gl_context_api(void)773 epoxy_egl_get_current_gl_context_api(void)
774 {
775 EGLint curapi;
776
777 if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
778 EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
779 (void)eglGetError();
780 return EGL_NONE;
781 }
782
783 return (EGLenum) curapi;
784 }
785 #endif /* PLATFORM_HAS_EGL */
786
787 /**
788 * Performs the dlsym() for the core GL 1.0 functions that we use for
789 * determining version and extension support for deciding on dlsym
790 * versus glXGetProcAddress() for all other functions.
791 *
792 * This needs to succeed on implementations without GLX (since
793 * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
794 * at call time we don't know for sure what API they're trying to use
795 * without inspecting contexts ourselves).
796 */
797 void *
epoxy_get_bootstrap_proc_address(const char * name)798 epoxy_get_bootstrap_proc_address(const char *name)
799 {
800 /* If we already have a library that links to libglapi loaded,
801 * use that.
802 */
803 #if PLATFORM_HAS_GLX
804 if (api.glx_handle && glXGetCurrentContext())
805 return epoxy_gl_dlsym(name);
806 #endif
807
808 /* If epoxy hasn't loaded any API-specific library yet, try to
809 * figure out what API the context is using and use that library,
810 * since future calls will also use that API (this prevents a
811 * non-X11 ES2 context from loading a bunch of X11 junk).
812 */
813 #if PLATFORM_HAS_EGL
814 get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
815 if (api.egl_handle) {
816 int version = 0;
817 switch (epoxy_egl_get_current_gl_context_api()) {
818 case EGL_OPENGL_API:
819 return epoxy_gl_dlsym(name);
820 case EGL_OPENGL_ES_API:
821 if (eglQueryContext(eglGetCurrentDisplay(),
822 eglGetCurrentContext(),
823 EGL_CONTEXT_CLIENT_VERSION,
824 &version)) {
825 if (version >= 2)
826 return epoxy_gles2_dlsym(name);
827 else
828 return epoxy_gles1_dlsym(name);
829 }
830 }
831 }
832 #endif /* PLATFORM_HAS_EGL */
833
834 /* Fall back to GLX */
835 return epoxy_gl_dlsym(name);
836 }
837
838 void *
epoxy_get_proc_address(const char * name)839 epoxy_get_proc_address(const char *name)
840 {
841 #if PLATFORM_HAS_EGL
842 GLenum egl_api = EGL_NONE;
843
844 if (!epoxy_current_context_is_glx())
845 egl_api = epoxy_egl_get_current_gl_context_api();
846
847 switch (egl_api) {
848 case EGL_OPENGL_API:
849 case EGL_OPENGL_ES_API:
850 return eglGetProcAddress(name);
851 case EGL_NONE:
852 break;
853 }
854 #endif
855
856 #if defined(_WIN32)
857 return wglGetProcAddress(name);
858 #elif defined(__APPLE__)
859 return epoxy_gl_dlsym(name);
860 #elif PLATFORM_HAS_GLX
861 if (epoxy_current_context_is_glx())
862 return glXGetProcAddressARB((const GLubyte *)name);
863 assert(0 && "Couldn't find current GLX or EGL context.\n");
864 #endif
865
866 return NULL;
867 }
868
869 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glBegin)870 WRAPPER(epoxy_glBegin)(GLenum primtype)
871 {
872 #ifdef _WIN32
873 InterlockedIncrement(&api.begin_count);
874 #else
875 pthread_mutex_lock(&api.mutex);
876 api.begin_count++;
877 pthread_mutex_unlock(&api.mutex);
878 #endif
879
880 epoxy_glBegin_unwrapped(primtype);
881 }
882
883 WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glEnd)884 WRAPPER(epoxy_glEnd)(void)
885 {
886 epoxy_glEnd_unwrapped();
887
888 #ifdef _WIN32
889 InterlockedDecrement(&api.begin_count);
890 #else
891 pthread_mutex_lock(&api.mutex);
892 api.begin_count--;
893 pthread_mutex_unlock(&api.mutex);
894 #endif
895 }
896
897 PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
898 PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
899
900 epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
901
902 /**
903 * Sets the function that will be called every time Epoxy fails to
904 * resolve a symbol.
905 *
906 * @param handler The new handler function
907 * @return The previous handler function
908 */
909 epoxy_resolver_failure_handler_t
epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)910 epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
911 {
912 #ifdef _WIN32
913 return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
914 handler);
915 #else
916 epoxy_resolver_failure_handler_t old;
917 pthread_mutex_lock(&api.mutex);
918 old = epoxy_resolver_failure_handler;
919 epoxy_resolver_failure_handler = handler;
920 pthread_mutex_unlock(&api.mutex);
921 return old;
922 #endif
923 }
924